Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
f6b1c1cf73
commit
5fb12406ad
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
# Cop supports --autocorrect.
|
||||
RSpec/BeforeAll:
|
||||
Exclude:
|
||||
- 'ee/spec/support/shared_examples/finders/security/findings_finder_shared_examples.rb'
|
||||
|
|
@ -168,7 +168,10 @@ export default {
|
|||
const files = prepareDiffData({ diff: data });
|
||||
const [newFileData] = files.filter((f) => f.file_hash === file.file_hash);
|
||||
const selectedFile = state.diffFiles.find((f) => f.file_hash === file.file_hash);
|
||||
Object.assign(selectedFile, { ...newFileData });
|
||||
Object.assign(selectedFile, {
|
||||
...newFileData,
|
||||
whitespaceOnlyChange: selectedFile.whitespaceOnlyChange,
|
||||
});
|
||||
},
|
||||
|
||||
[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { discussion, diffPositionByLineCode, hash }) {
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ export function getFormData(params) {
|
|||
width: params.width,
|
||||
height: params.height,
|
||||
line_range: lineRange,
|
||||
ignore_whitespace_change: !showWhitespace,
|
||||
ignore_whitespace_change: diffFile.whitespaceOnlyChange ? false : !showWhitespace,
|
||||
});
|
||||
|
||||
const postData = {
|
||||
|
|
@ -390,6 +390,7 @@ function finalizeDiffFile(file) {
|
|||
isLoadingFullFile: false,
|
||||
discussions: [],
|
||||
renderingLines: false,
|
||||
whitespaceOnlyChange: file.viewer?.whitespace_only,
|
||||
});
|
||||
|
||||
return file;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export const TYPENAME_CI_PIPELINE = 'Ci::Pipeline';
|
|||
export const TYPENAME_CI_RUNNER = 'Ci::Runner';
|
||||
export const TYPENAME_CI_VARIABLE = 'Ci::Variable';
|
||||
export const TYPENAME_COMMIT_STATUS = 'CommitStatus';
|
||||
export const TYPENAME_CONTAINER_REPOSITORY = 'ContainerRepository';
|
||||
export const TYPENAME_CRM_CONTACT = 'CustomerRelations::Contact';
|
||||
export const TYPENAME_CRM_ORGANIZATION = 'CustomerRelations::Organization';
|
||||
export const TYPENAME_DESIGN_VERSION = 'DesignManagement::Version';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
<script>
|
||||
import { GlLoadingIcon, GlAlert, GlModal } from '@gitlab/ui';
|
||||
import CodeBlockHighlighted from '~/vue_shared/components/code_block_highlighted.vue';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import { TYPENAME_CONTAINER_REPOSITORY } from '~/graphql_shared/constants';
|
||||
import { __ } from '~/locale';
|
||||
import getManifestDetailsQuery from '../../graphql/queries/get_manifest_details.query.graphql';
|
||||
|
||||
export default {
|
||||
components: { GlLoadingIcon, GlAlert, GlModal, CodeBlockHighlighted },
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
digest: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
manifestDetails: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
prettyFormattedDetails() {
|
||||
try {
|
||||
// Workaround for backend returning a serialized Ruby hash. The only difference between the hash and JSON is
|
||||
// that it uses '=>' instead of ':', so we'll replace it and try to parse it as JSON.
|
||||
const details = this.manifestDetails.replaceAll('=>', ':');
|
||||
const json = JSON.parse(details);
|
||||
return JSON.stringify(json, null, 2);
|
||||
} catch {
|
||||
// Use the raw manifest details if it couldn't be parsed.
|
||||
return this.manifestDetails;
|
||||
}
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
manifestDetails: {
|
||||
query: getManifestDetailsQuery,
|
||||
variables() {
|
||||
return {
|
||||
id: convertToGraphQLId(TYPENAME_CONTAINER_REPOSITORY, this.$route.params.id),
|
||||
reference: this.digest,
|
||||
};
|
||||
},
|
||||
update({ containerRepository }) {
|
||||
return containerRepository.manifest;
|
||||
},
|
||||
skip() {
|
||||
return !this.digest;
|
||||
},
|
||||
error() {
|
||||
this.manifestDetails = null;
|
||||
},
|
||||
},
|
||||
},
|
||||
cancel: { text: __('Close') },
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-modal
|
||||
modal-id="signature-details-modal"
|
||||
:visible="visible"
|
||||
:title="s__('ContainerRegistry|Signature details')"
|
||||
:action-cancel="$options.cancel"
|
||||
scrollable
|
||||
@hidden="$emit('close')"
|
||||
>
|
||||
<gl-loading-icon v-if="$apollo.queries.manifestDetails.loading" size="lg" />
|
||||
|
||||
<gl-alert v-else-if="!manifestDetails" :dismissible="false" variant="danger">
|
||||
{{ s__('ContainerRegistry|Could not load signature details.') }}
|
||||
</gl-alert>
|
||||
|
||||
<code-block-highlighted v-else language="json" :code="prettyFormattedDetails" />
|
||||
</gl-modal>
|
||||
</template>
|
||||
|
|
@ -6,6 +6,7 @@ import {
|
|||
GlIcon,
|
||||
GlDisclosureDropdown,
|
||||
GlBadge,
|
||||
GlLink,
|
||||
} from '@gitlab/ui';
|
||||
import { formatDate } from '~/lib/utils/datetime_utility';
|
||||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
|
|
@ -27,6 +28,7 @@ import {
|
|||
MORE_ACTIONS_TEXT,
|
||||
COPY_IMAGE_PATH_TITLE,
|
||||
} from '../../constants/index';
|
||||
import SignatureDetailsModal from './signature_details_modal.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -35,10 +37,12 @@ export default {
|
|||
GlIcon,
|
||||
GlDisclosureDropdown,
|
||||
GlBadge,
|
||||
GlLink,
|
||||
ListItem,
|
||||
ClipboardButton,
|
||||
TimeAgoTooltip,
|
||||
DetailsRow,
|
||||
SignatureDetailsModal,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
|
|
@ -283,7 +287,7 @@ export default {
|
|||
|
||||
<template v-if="signatures.length" #details-signatures>
|
||||
<details-row
|
||||
v-for="(signature, index) in signatures"
|
||||
v-for="({ digest }, index) in signatures"
|
||||
:key="index"
|
||||
icon="pencil"
|
||||
data-testid="signatures-detail"
|
||||
|
|
@ -291,11 +295,21 @@ export default {
|
|||
<div class="gl-display-flex">
|
||||
<span class="gl-text-truncate gl-mr-3 gl-flex-basis-0 gl-flex-grow-1">
|
||||
<gl-sprintf :message="s__('ContainerRegistry|Signature digest: %{digest}')">
|
||||
<template #digest>{{ signature.digest }}</template>
|
||||
<template #digest>{{ digest }}</template>
|
||||
</gl-sprintf>
|
||||
</span>
|
||||
|
||||
<gl-link @click="selectedDigest = digest">
|
||||
{{ __('View details') }}
|
||||
</gl-link>
|
||||
</div>
|
||||
</details-row>
|
||||
|
||||
<signature-details-modal
|
||||
:visible="Boolean(selectedDigest)"
|
||||
:digest="selectedDigest"
|
||||
@close="selectedDigest = null"
|
||||
/>
|
||||
</template>
|
||||
</list-item>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
query getManifestDetails($id: ContainerRepositoryID!, $reference: String!) {
|
||||
containerRepository(id: $id) {
|
||||
id
|
||||
manifest(reference: $reference)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,12 +10,18 @@ import ProtectedTagEditList from '~/protected_tags/protected_tag_edit_list';
|
|||
import initSettingsPanels from '~/settings_panels';
|
||||
|
||||
export default () => {
|
||||
new ProtectedTagCreate({ hasLicense: false });
|
||||
new ProtectedTagEditList({ hasLicense: false });
|
||||
initDeployKeys();
|
||||
initSettingsPanels();
|
||||
new ProtectedBranchCreate({ hasLicense: false });
|
||||
new ProtectedBranchEditList();
|
||||
initDatePicker(); // Used for deploy token "expires at" field
|
||||
fileUpload('.js-choose-file', '.js-object-map-input');
|
||||
if (gon.limit_repository_settings?.includes('protected_branches')) {
|
||||
new ProtectedBranchCreate({ hasLicense: false });
|
||||
new ProtectedBranchEditList();
|
||||
} else {
|
||||
new ProtectedTagCreate({ hasLicense: false });
|
||||
new ProtectedTagEditList({ hasLicense: false });
|
||||
initDeployKeys();
|
||||
initSettingsPanels();
|
||||
new ProtectedBranchCreate({ hasLicense: false });
|
||||
new ProtectedBranchEditList();
|
||||
initDatePicker(); // Used for deploy token "expires at" field
|
||||
fileUpload('.js-choose-file', '.js-object-map-input');
|
||||
new ProtectedBranchEditList();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ export const getGroups = ({ withProjectAccess = false }) => {
|
|||
};
|
||||
|
||||
export const getDeployKeys = (query) => {
|
||||
if (gon.limit_repository_settings) {
|
||||
return { data: [] };
|
||||
}
|
||||
|
||||
return axios.get(buildUrl(gon.relative_url_root || '', DEPLOY_KEYS_PATH), {
|
||||
params: {
|
||||
search: query,
|
||||
|
|
|
|||
|
|
@ -230,37 +230,42 @@ export default {
|
|||
this.initialLoading = initial;
|
||||
this.loading = true;
|
||||
|
||||
let asyncKeysUsersAndGroups;
|
||||
|
||||
if (this.hasLicense) {
|
||||
Promise.all([
|
||||
getDeployKeys(this.query),
|
||||
getUsers(this.query),
|
||||
this.groups.length
|
||||
? Promise.resolve({ data: this.groups })
|
||||
: getGroups({ withProjectAccess: this.groupsWithProjectAccess }),
|
||||
])
|
||||
.then(([deployKeysResponse, usersResponse, groupsResponse]) => {
|
||||
this.consolidateData(deployKeysResponse.data, usersResponse.data, groupsResponse.data);
|
||||
this.setSelected({ initial });
|
||||
})
|
||||
.catch(() =>
|
||||
createAlert({ message: __('Failed to load groups, users and deploy keys.') }),
|
||||
)
|
||||
.finally(() => {
|
||||
this.initialLoading = false;
|
||||
this.loading = false;
|
||||
});
|
||||
if (gon.limit_repository_settings?.includes('protected_branches')) {
|
||||
asyncKeysUsersAndGroups = Promise.all([
|
||||
null,
|
||||
getUsers(this.query),
|
||||
this.groups.length
|
||||
? this.groups
|
||||
: getGroups({ withProjectAccess: this.groupsWithProjectAccess }),
|
||||
]);
|
||||
} else {
|
||||
asyncKeysUsersAndGroups = Promise.all([
|
||||
getDeployKeys(this.query),
|
||||
getUsers(this.query),
|
||||
this.groups.length
|
||||
? this.groups
|
||||
: getGroups({ withProjectAccess: this.groupsWithProjectAccess }),
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
getDeployKeys(this.query)
|
||||
.then((deployKeysResponse) => {
|
||||
this.consolidateData(deployKeysResponse.data);
|
||||
this.setSelected({ initial });
|
||||
})
|
||||
.catch(() => createAlert({ message: __('Failed to load deploy keys.') }))
|
||||
.finally(() => {
|
||||
this.initialLoading = false;
|
||||
this.loading = false;
|
||||
});
|
||||
asyncKeysUsersAndGroups = Promise.all([getDeployKeys(this.query), null, null]);
|
||||
}
|
||||
|
||||
asyncKeysUsersAndGroups
|
||||
.then((data) => {
|
||||
this.consolidateData(...data);
|
||||
this.setSelected({ initial });
|
||||
})
|
||||
.catch(() => {
|
||||
createAlert({ message: __('Failed to load data.') });
|
||||
})
|
||||
.finally(() => {
|
||||
this.initialLoading = false;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
consolidateData(deployKeysResponse, usersResponse = [], groupsResponse = []) {
|
||||
// This re-assignment is intentional as level.type property is being used for comparision,
|
||||
|
|
@ -269,42 +274,48 @@ export default {
|
|||
this.roles = this.accessLevelsData.map((role) => ({ ...role, type: LEVEL_TYPES.ROLE }));
|
||||
|
||||
if (this.hasLicense) {
|
||||
this.groups = groupsResponse.map((group) => ({ ...group, type: LEVEL_TYPES.GROUP }));
|
||||
this.groups = groupsResponse
|
||||
? groupsResponse.data.map((group) => ({ ...group, type: LEVEL_TYPES.GROUP }))
|
||||
: [];
|
||||
|
||||
// Has to be checked against server response
|
||||
// because the selected item can be in filter results
|
||||
if (this.showUsers) {
|
||||
this.users = usersResponse.map(({ id, name, username, avatar_url }) => ({
|
||||
id,
|
||||
name,
|
||||
username,
|
||||
avatar_url,
|
||||
type: LEVEL_TYPES.USER,
|
||||
}));
|
||||
this.users = usersResponse
|
||||
? usersResponse.data.map(({ id, name, username, avatar_url }) => ({
|
||||
id,
|
||||
name,
|
||||
username,
|
||||
avatar_url,
|
||||
type: LEVEL_TYPES.USER,
|
||||
}))
|
||||
: [];
|
||||
}
|
||||
}
|
||||
|
||||
this.deployKeys = deployKeysResponse.map((response) => {
|
||||
const {
|
||||
id,
|
||||
fingerprint,
|
||||
fingerprint_sha256: fingerprintSha256,
|
||||
title,
|
||||
owner: { avatar_url, name, username },
|
||||
} = response;
|
||||
this.deployKeys = deployKeysResponse
|
||||
? deployKeysResponse.data.map((response) => {
|
||||
const {
|
||||
id,
|
||||
fingerprint,
|
||||
fingerprint_sha256: fingerprintSha256,
|
||||
title,
|
||||
owner: { avatar_url, name, username },
|
||||
} = response;
|
||||
|
||||
const availableFingerprint = fingerprintSha256 || fingerprint;
|
||||
const shortFingerprint = `(${availableFingerprint.substring(0, 14)}...)`;
|
||||
const availableFingerprint = fingerprintSha256 || fingerprint;
|
||||
const shortFingerprint = `(${availableFingerprint.substring(0, 14)}...)`;
|
||||
|
||||
return {
|
||||
id,
|
||||
title: title.concat(' ', shortFingerprint),
|
||||
avatar_url,
|
||||
fullname: name,
|
||||
username,
|
||||
type: LEVEL_TYPES.DEPLOY_KEY,
|
||||
};
|
||||
});
|
||||
return {
|
||||
id,
|
||||
title: title.concat(' ', shortFingerprint),
|
||||
avatar_url,
|
||||
fullname: name,
|
||||
username,
|
||||
type: LEVEL_TYPES.DEPLOY_KEY,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
},
|
||||
setSelected({ initial } = {}) {
|
||||
if (initial) {
|
||||
|
|
|
|||
|
|
@ -147,6 +147,11 @@ export default class ProtectedBranchCreate {
|
|||
if (!this.hasProtectedBranchSuccessAlert()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!document.getElementById('branch-rules')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.expandAndScroll(PROTECTED_BRANCHES_ANCHOR);
|
||||
|
||||
this.createSuccessAlert();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ class Projects::ProtectedRefsController < Projects::ApplicationController
|
|||
include RepositorySettingsRedirect
|
||||
|
||||
# Authorize
|
||||
before_action :authorize_admin_project!
|
||||
before_action :authorize_admin_protected_refs!
|
||||
before_action :load_protected_ref, only: [:show, :update, :destroy]
|
||||
|
||||
layout "project_settings"
|
||||
|
|
@ -51,6 +51,10 @@ class Projects::ProtectedRefsController < Projects::ApplicationController
|
|||
|
||||
protected
|
||||
|
||||
def authorize_admin_protected_refs!
|
||||
authorize_admin_project!
|
||||
end
|
||||
|
||||
def create_service_class
|
||||
service_namespace::CreateService
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ module Projects
|
|||
class BranchRulesController < Projects::ApplicationController
|
||||
before_action :authorize_admin_project!
|
||||
before_action do
|
||||
push_frontend_feature_flag(:approval_rules_drawer, @project)
|
||||
push_frontend_feature_flag(:edit_branch_rules, @project)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,6 @@ module Projects
|
|||
|
||||
feature_category :code_review_workflow
|
||||
|
||||
before_action do
|
||||
push_frontend_feature_flag(:approval_rules_drawer, @project)
|
||||
end
|
||||
|
||||
def update
|
||||
result = ::Projects::UpdateService.new(@project, current_user, project_params).execute
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ module Packages
|
|||
end
|
||||
|
||||
def execute
|
||||
return ::Packages::Package.none unless query
|
||||
return ::Packages::Conan::Package.none unless query
|
||||
|
||||
packages
|
||||
end
|
||||
|
|
@ -23,7 +23,6 @@ module Packages
|
|||
|
||||
def packages
|
||||
base
|
||||
.conan
|
||||
.installable
|
||||
.preload_conan_metadatum
|
||||
.with_name_like(query)
|
||||
|
|
@ -31,15 +30,7 @@ module Packages
|
|||
end
|
||||
|
||||
def base
|
||||
project ? packages_of_project : packages_for_current_user
|
||||
end
|
||||
|
||||
def packages_of_project
|
||||
project.packages
|
||||
end
|
||||
|
||||
def packages_for_current_user
|
||||
Packages::Package.for_projects(projects_visible_to_current_user)
|
||||
::Packages::Conan::Package.for_projects(project || projects_visible_to_current_user)
|
||||
end
|
||||
|
||||
def projects_visible_to_current_user
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module ProtectedBranchesHelper
|
|||
if protected_branch_entity.is_a?(Group)
|
||||
can?(current_user, :admin_group, protected_branch_entity)
|
||||
else
|
||||
can?(current_user, :admin_project, protected_branch_entity)
|
||||
can?(current_user, :admin_protected_branch, protected_branch_entity)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ module Ci
|
|||
include FastDestroyAll::Helpers
|
||||
|
||||
include IgnorableColumns
|
||||
ignore_column :id_convert_to_bigint, remove_with: '16.3', remove_after: '2023-08-22'
|
||||
ignore_column :id_convert_to_bigint, remove_with: '17.2', remove_after: '2024-06-15'
|
||||
|
||||
MAX_OPEN_MERGE_REQUESTS_REFS = 4
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
class Packages::Conan::Metadatum < ApplicationRecord
|
||||
NONE_VALUE = '_'
|
||||
|
||||
belongs_to :package, -> { where(package_type: :conan) }, inverse_of: :conan_metadatum
|
||||
belongs_to :package, class_name: 'Packages::Conan::Package', inverse_of: :conan_metadatum
|
||||
|
||||
validates :package, presence: true
|
||||
|
||||
|
|
@ -12,7 +12,6 @@ class Packages::Conan::Metadatum < ApplicationRecord
|
|||
presence: true,
|
||||
format: { with: Gitlab::Regex.conan_recipe_user_channel_regex }
|
||||
|
||||
validate :conan_package_type
|
||||
validate :username_channel_none_values
|
||||
|
||||
def recipe
|
||||
|
|
@ -42,15 +41,9 @@ class Packages::Conan::Metadatum < ApplicationRecord
|
|||
|
||||
private
|
||||
|
||||
def conan_package_type
|
||||
unless package&.conan?
|
||||
errors.add(:base, _('Package type must be Conan'))
|
||||
end
|
||||
end
|
||||
|
||||
def username_channel_none_values
|
||||
self.class.validate_username_and_channel(package_username, package_channel) do |none_field|
|
||||
errors.add("package_#{none_field}".to_sym, _("can't be solely blank"))
|
||||
errors.add(:"package_#{none_field}", _("can't be solely blank"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Packages
|
||||
module Conan
|
||||
class Package < Packages::Package
|
||||
self.allow_legacy_sti_class = true
|
||||
|
||||
INSTALLABLE_STATUSES = %i[default hidden].freeze
|
||||
|
||||
has_one :conan_metadatum, inverse_of: :package, class_name: 'Packages::Conan::Metadatum'
|
||||
|
||||
accepts_nested_attributes_for :conan_metadatum
|
||||
|
||||
delegate :recipe, :recipe_path, to: :conan_metadatum, prefix: :conan
|
||||
|
||||
validates :name, :version, format: { with: Gitlab::Regex.conan_recipe_component_regex }
|
||||
validate :valid_conan_package_recipe
|
||||
|
||||
scope :with_conan_channel, ->(package_channel) do
|
||||
joins(:conan_metadatum).where(packages_conan_metadata: { package_channel: package_channel })
|
||||
end
|
||||
|
||||
scope :with_conan_username, ->(package_username) do
|
||||
joins(:conan_metadatum).where(packages_conan_metadata: { package_username: package_username })
|
||||
end
|
||||
|
||||
scope :preload_conan_metadatum, -> { preload(:conan_metadatum) }
|
||||
|
||||
private
|
||||
|
||||
def valid_conan_package_recipe
|
||||
return unless self.class
|
||||
.for_projects(project)
|
||||
.includes(:conan_metadatum)
|
||||
.not_pending_destruction
|
||||
.with_name(name)
|
||||
.with_version(version)
|
||||
.with_conan_channel(conan_metadatum.package_channel)
|
||||
.with_conan_username(conan_metadatum.package_username)
|
||||
.id_not_in(id)
|
||||
.exists?
|
||||
|
||||
errors.add(:base, _('Package recipe already exists'))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -45,7 +45,6 @@ class Packages::Package < ApplicationRecord
|
|||
has_many :installable_nuget_package_files, -> { installable.with_nuget_format }, class_name: 'Packages::PackageFile', inverse_of: :package
|
||||
has_many :dependency_links, inverse_of: :package, class_name: 'Packages::DependencyLink'
|
||||
has_many :tags, inverse_of: :package, class_name: 'Packages::Tag'
|
||||
has_one :conan_metadatum, inverse_of: :package, class_name: 'Packages::Conan::Metadatum'
|
||||
has_one :pypi_metadatum, inverse_of: :package, class_name: 'Packages::Pypi::Metadatum'
|
||||
has_one :maven_metadatum, inverse_of: :package, class_name: 'Packages::Maven::Metadatum'
|
||||
has_one :nuget_metadatum, inverse_of: :package, class_name: 'Packages::Nuget::Metadatum'
|
||||
|
|
@ -60,11 +59,9 @@ class Packages::Package < ApplicationRecord
|
|||
has_one :debian_distribution, through: :debian_publication, source: :distribution, inverse_of: :packages, class_name: 'Packages::Debian::ProjectDistribution'
|
||||
has_many :matching_package_protection_rules, -> (package) { where(package_type: package.package_type).for_package_name(package.name) }, through: :project, source: :package_protection_rules
|
||||
|
||||
accepts_nested_attributes_for :conan_metadatum
|
||||
accepts_nested_attributes_for :debian_publication
|
||||
accepts_nested_attributes_for :maven_metadatum
|
||||
|
||||
delegate :recipe, :recipe_path, to: :conan_metadatum, prefix: :conan
|
||||
delegate :codename, :suite, to: :debian_distribution, prefix: :debian_distribution
|
||||
delegate :target_sha, to: :composer_metadatum, prefix: :composer
|
||||
|
||||
|
|
@ -80,11 +77,9 @@ class Packages::Package < ApplicationRecord
|
|||
},
|
||||
unless: -> { pending_destruction? || conan? }
|
||||
|
||||
validate :valid_conan_package_recipe, if: :conan?
|
||||
validate :valid_composer_global_name, if: :composer?
|
||||
validate :npm_package_already_taken, if: :npm?
|
||||
|
||||
validates :name, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan?
|
||||
validates :name, format: { with: Gitlab::Regex.generic_package_name_regex }, if: :generic?
|
||||
validates :name, format: { with: Gitlab::Regex.helm_package_regex }, if: :helm?
|
||||
validates :name, format: { with: Gitlab::Regex.npm_package_name_regex, message: Gitlab::Regex.npm_package_name_regex_message }, if: :npm?
|
||||
|
|
@ -93,7 +88,6 @@ class Packages::Package < ApplicationRecord
|
|||
validates :name, format: { with: Gitlab::Regex.debian_package_name_regex }, if: :debian_package?
|
||||
validates :name, inclusion: { in: [Packages::Debian::INCOMING_PACKAGE_NAME] }, if: :debian_incoming?
|
||||
validates :version, format: { with: Gitlab::Regex.nuget_version_regex }, if: :nuget?
|
||||
validates :version, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan?
|
||||
validates :version, format: { with: Gitlab::Regex.maven_version_regex }, if: -> { version? && maven? }
|
||||
validates :version, format: { with: Gitlab::Regex.pypi_version_regex }, if: :pypi?
|
||||
validates :version, format: { with: Gitlab::Regex.helm_version_regex }, if: :helm?
|
||||
|
|
@ -154,13 +148,6 @@ class Packages::Package < ApplicationRecord
|
|||
scope :including_dependency_links, -> { includes(dependency_links: :dependency) }
|
||||
scope :including_dependency_links_with_nuget_metadatum, -> { includes(dependency_links: [:dependency, :nuget_metadatum]) }
|
||||
|
||||
scope :with_conan_channel, ->(package_channel) do
|
||||
joins(:conan_metadatum).where(packages_conan_metadata: { package_channel: package_channel })
|
||||
end
|
||||
scope :with_conan_username, ->(package_username) do
|
||||
joins(:conan_metadatum).where(packages_conan_metadata: { package_username: package_username })
|
||||
end
|
||||
|
||||
scope :with_debian_codename, ->(codename) do
|
||||
joins(:debian_distribution).where(Packages::Debian::ProjectDistribution.table_name => { codename: codename })
|
||||
end
|
||||
|
|
@ -178,7 +165,6 @@ class Packages::Package < ApplicationRecord
|
|||
scope :preload_npm_metadatum, -> { preload(:npm_metadatum) }
|
||||
scope :preload_nuget_metadatum, -> { preload(:nuget_metadatum) }
|
||||
scope :preload_pypi_metadatum, -> { preload(:pypi_metadatum) }
|
||||
scope :preload_conan_metadatum, -> { preload(:conan_metadatum) }
|
||||
|
||||
scope :with_npm_scope, ->(scope) do
|
||||
npm.where("position('/' in packages_packages.name) > 0 AND split_part(packages_packages.name, '/', 1) = :package_scope", package_scope: "@#{sanitize_sql_like(scope)}")
|
||||
|
|
@ -232,7 +218,8 @@ class Packages::Package < ApplicationRecord
|
|||
def self.inheritance_column_to_class_map = {
|
||||
ml_model: 'Packages::MlModel::Package',
|
||||
golang: 'Packages::Go::Package',
|
||||
rubygems: 'Packages::Rubygems::Package'
|
||||
rubygems: 'Packages::Rubygems::Package',
|
||||
conan: 'Packages::Conan::Package'
|
||||
}.freeze
|
||||
|
||||
def self.only_maven_packages_with_path(path, use_cte: false)
|
||||
|
|
@ -401,21 +388,6 @@ class Packages::Package < ApplicationRecord
|
|||
composer? && !Gitlab::Regex.composer_dev_version_regex.match(version.to_s)
|
||||
end
|
||||
|
||||
def valid_conan_package_recipe
|
||||
recipe_exists = project.packages
|
||||
.conan
|
||||
.includes(:conan_metadatum)
|
||||
.not_pending_destruction
|
||||
.with_name(name)
|
||||
.with_version(version)
|
||||
.with_conan_channel(conan_metadatum.package_channel)
|
||||
.with_conan_username(conan_metadatum.package_username)
|
||||
.id_not_in(id)
|
||||
.exists?
|
||||
|
||||
errors.add(:base, _('Package recipe already exists')) if recipe_exists
|
||||
end
|
||||
|
||||
def valid_composer_global_name
|
||||
# .default_scoped is required here due to a bug in rails that leaks
|
||||
# the scope and adds `self` to the query incorrectly
|
||||
|
|
|
|||
|
|
@ -607,6 +607,8 @@ class ProjectPolicy < BasePolicy
|
|||
enable :admin_push_rules
|
||||
enable :manage_deploy_tokens
|
||||
enable :manage_merge_request_settings
|
||||
enable :create_protected_branch
|
||||
enable :admin_protected_branch
|
||||
end
|
||||
|
||||
rule { can?(:admin_build) }.enable :manage_trigger
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ module Packages
|
|||
package_detail[:maven_metadatum] = @package.maven_metadatum if @package.maven_metadatum
|
||||
package_detail[:nuget_metadatum] = @package.nuget_metadatum if @package.nuget_metadatum
|
||||
package_detail[:composer_metadatum] = @package.composer_metadatum if @package.composer_metadatum
|
||||
package_detail[:conan_metadatum] = @package.conan_metadatum if @package.conan_metadatum
|
||||
package_detail[:conan_metadatum] = @package.conan_metadatum if @package.conan? && @package.conan_metadatum
|
||||
package_detail[:dependency_links] = @package.dependency_links.map { |link| build_dependency_links(link) }
|
||||
package_detail[:pipeline] = build_pipeline_info(@package.pipeline) if @package.pipeline
|
||||
package_detail[:pipelines] = build_pipeline_infos(@package.pipelines) if @package.pipelines.present?
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ module Packages
|
|||
end
|
||||
|
||||
def package
|
||||
project
|
||||
.packages
|
||||
::Packages::Conan::Package
|
||||
.for_projects(project)
|
||||
.with_name(name)
|
||||
.with_version(version)
|
||||
.order_created
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
-# The shared parts of the views can be found in the `shared` directory.
|
||||
-# Those are used throughout the actual views. These `shared` views are then
|
||||
-# reused in EE.
|
||||
- if can?(current_user, :admin_protected_branch, @project)
|
||||
= render "projects/settings/repository/protected_branches", protected_branch_entity: @project
|
||||
|
||||
- if current_user.can?(:manage_deploy_tokens, @project)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ module PauseControl
|
|||
|
||||
pause_strategies_workers.each do |strategy, workers|
|
||||
strategy_klass = Gitlab::SidekiqMiddleware::PauseControl.for(strategy)
|
||||
|
||||
next if strategy_klass.should_pause?
|
||||
|
||||
workers.each do |worker|
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: approval_rules_drawer
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/439397
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146502
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/444628
|
||||
milestone: '16.10'
|
||||
group: group::source code
|
||||
type: beta
|
||||
default_enabled: true
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: zoekt_pause_indexing
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126027
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/417597
|
||||
milestone: '16.3'
|
||||
type: ops
|
||||
group: group::global search
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
- name: CI/CD Catalog with components and inputs now generally available
|
||||
description: |
|
||||
The CI/CD Catalog is now generally available. As part of this release, we're also making [CI/CD components](https://docs.gitlab.com/ee/ci/components/) and [inputs](https://docs.gitlab.com/ee/ci/yaml/inputs.html) generally available.
|
||||
|
||||
With the CI/CD Catalog, you gain access to a vast array of components created by the community and industry experts.
|
||||
Whether you're seeking solutions for continuous integration, deployment pipelines, or automation tasks, you'll find a diverse selection of components tailored to suit your requirements.
|
||||
You can read more about the Catalog and its features in the following [blog post](https://about.gitlab.com/blog/2024/05/08/ci-cd-catalog-goes-ga-no-more-building-pipelines-from-scratch/).
|
||||
|
||||
You're invited to contribute CI/CD components to the Catalog and help expand this new and growing part of GitLab.com!
|
||||
stage: verify
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
available_in: [Free, Premium, Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/ci/components/#cicd-catalog
|
||||
image_url: https://img.youtube.com/vi/QDn77nwIb-o/hqdefault.jpg
|
||||
published_at: 2024-05-16
|
||||
release: 17.0
|
||||
|
||||
- name: AI Impact analytics in the Value Streams Dashboard
|
||||
description: |
|
||||
AI Impact is a dashboard available in the Value Streams Dashboard that helps organizations understand the [impact of GitLab Duo on their productivity](https://about.gitlab.com/blog/2024/02/20/measuring-ai-effectiveness-beyond-developer-productivity-metrics/).
|
||||
This new month-over-month metric view compares the AI Usage trends with SDLC metrics like lead time, cycle time, DORA, and vulnerabilities. Software leaders can use the AI Impact dashboard to measure how much time is saved in their end-to-end workstream, while staying focused on business outcomes rather than developer activity.
|
||||
|
||||
In this first release, the AI usage is measured as the monthly [Code Suggestions](https://docs.gitlab.com/ee/user/project/repository/code_suggestions/) usage rate, and is calculated as the number of monthly unique Code Suggestions users divided by total monthly unique [contributors](https://docs.gitlab.com/ee/user/group/contribution_analytics/).
|
||||
|
||||
The AI Impact dashboard is available to users on the Ultimate tier for a limited time. Afterwards, a GitLab Duo Enterprise license will be required to use the dashboard.
|
||||
stage: plan
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
available_in: [Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/user/analytics/value_streams_dashboard.html#ai-impact-analytics
|
||||
image_url: https://about.gitlab.com/images/17_0/17.0_vsd_ai2.png
|
||||
published_at: 2024-05-16
|
||||
release: 17.0
|
||||
|
||||
- name: Introducing hosted runners on Linux Arm
|
||||
description: |
|
||||
We are excited to introduce hosted runners on Linux Arm for GitLab.com.
|
||||
The now available `medium` and `large` Arm machine types, equipped with 4 and 8 vCPUs respectively, and fully integrated with GitLab CI/CD, will allow you to build and test your application faster and more cost-efficient than ever before.
|
||||
|
||||
We are determined to provide the industry's fastest CI/CD build speed and look forward to seeing teams achieve even shorter feedback cycles and ultimately deliver software faster.
|
||||
stage: verify
|
||||
self-managed: false
|
||||
gitlab-com: true
|
||||
available_in: [Premium, Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/ci/runners/hosted_runners/linux.html
|
||||
image_url: https://about.gitlab.com/images/17_0/larger-runners.png
|
||||
published_at: 2024-05-16
|
||||
release: 17.0
|
||||
|
||||
- name: Introducing deployment detail pages
|
||||
description: |
|
||||
You can now link directly to a deployment in GitLab. Previously, if you were collaborating on a deployment, you had to look up the deployment from the deployment list. Because of the number of deployments listed, finding the correct deployment was difficult and prone to error.
|
||||
|
||||
From 17.0, GitLab offers a deployment details view that you can link to directly. In this first version, the deployment details page offers an overview of the deployment job and the possibility to approve, reject, or comment on a deployment in a continuous delivery setting. We are looking into further avenues to enhance the deployment details page, including by linking to it from the related pipeline job. We would love to hear your feedback in [issue 450700](https://gitlab.com/gitlab-org/gitlab/-/issues/450700).
|
||||
stage: verify
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
available_in: [Premium, Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/ci/environments/deployment_approvals.html#approve-or-reject-a-deployment
|
||||
image_url: https://about.gitlab.com/images/17_0/deployment-detail-page.png
|
||||
published_at: 2024-05-16
|
||||
release: 17.0
|
||||
|
||||
- name: GitLab Duo Chat now uses Anthropic Claude 3 Sonnet
|
||||
description: |
|
||||
GitLab Duo Chat just got a lot better. It now uses Anthropic Claude 3 Sonnet as the base model, replacing Claude 2.1 for answering most questions.
|
||||
|
||||
At GitLab, we apply a test-driven approach when choosing the best model for a set of tasks and authoring well-performing prompts. With recent adjustments to the chat prompts, we have achieved significant improvements in the correctness, comprehensiveness, and readability of chat answers based on Claude 3 Sonnet compared to the previous chat version built on Claude 2.1. Hence, we have now switched to this new model version.
|
||||
stage: ai-powered
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
available_in: [Premium, Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/user/ai_features.html#gitlab-duo-chat
|
||||
image_url: https://about.gitlab.com/images/17_0/gitlabduo.png
|
||||
published_at: 2024-05-16
|
||||
release: 17.0
|
||||
|
||||
- name: Enhanced context control with the `rules:exists` CI/CD keyword
|
||||
description: |
|
||||
The `rules:exists` CI/CD keyword has default behaviors that vary based on where the keyword is defined, which can make it harder to use with more complex pipelines. When defined in a job, `rules:exists` searches for specified files in the project running the pipeline. However, when defined in an `include` section, `rules:exists` searches for specified files in the project hosting the configuration file containing the `include` section. If configuration is split over multiple files and projects, it can be hard to know which exact project will be searched for defined files.
|
||||
|
||||
In this release, we have introduced `project` and `ref` subkeys to `rules:exists`, providing you a way to explicitly control the search context for this keyword. These new subkeys help you ensure accurate rule evaluation by precisely specifying the search context, mitigating inconsistencies, and enhancing clarity in your pipeline rule definitions.
|
||||
stage: verify
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
available_in: [Free, Premium, Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/ci/yaml/#rulesexistsproject
|
||||
image_url: https://about.gitlab.com/images/17_0/exists.png
|
||||
published_at: 2024-05-16
|
||||
release: 17.0
|
||||
|
||||
- name: Add a group to the CI/CD job token allowlist
|
||||
description: |
|
||||
Introduced in GitLab 15.9, the CI/CD job token allowlist prevents unauthorized access from other projects to your project. Previously, you could allow access at the project level from other specific projects only, with a maximum limit of 200 total projects.
|
||||
|
||||
In GitLab 17.0, you can now add groups to a project's CI/CD job token allowlist. The maximum limit of 200 now applies to both projects and groups, meaning a project allowlist can now have up to 200 projects and groups authorized for access. This improvement makes it easier to add large numbers of projects associated with a group.
|
||||
stage: verify
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
available_in: [Free, Premium, Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#control-job-token-access-to-your-project
|
||||
image_url: https://about.gitlab.com/images/17_0/verify-add-a-group-to-the-job-token-allowlist.png
|
||||
published_at: 2024-05-16
|
||||
release: 17.0
|
||||
|
||||
|
||||
- name: New usage overview panel in the Value Streams Dashboard
|
||||
description: |
|
||||
We enhanced the Value Streams Dashboard with an Overview panel. This new visualization addresses the need for executive-level insights into software delivery performance, and gives a clear picture of GitLab usage in the context of software development life cycle (SDLC).
|
||||
|
||||
The Overview panel displays metrics for the group level, such as number of (sub)groups, projects, users, issues, merge requests, and pipelines.
|
||||
stage: plan
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
available_in: [Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/user/analytics/value_streams_dashboard.html#overview-panel
|
||||
image_url: https://about.gitlab.com/images/17_0/vsd_overview_17.png
|
||||
published_at: 2024-05-16
|
||||
release: 17.0
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
table_name: packages_packages
|
||||
classes:
|
||||
- Packages::Conan::Package
|
||||
- Packages::Go::Package
|
||||
- Packages::MlModel::Package
|
||||
- Packages::Package
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CleanupBigintConversionsForCiPipelines < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.1'
|
||||
enable_lock_retries!
|
||||
|
||||
TABLE = :ci_pipelines
|
||||
COLUMNS = %i[id]
|
||||
|
||||
def up
|
||||
cleanup_conversion_of_integer_to_bigint(TABLE, COLUMNS)
|
||||
end
|
||||
|
||||
def down
|
||||
restore_conversion_of_integer_to_bigint(TABLE, COLUMNS)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
3b6c9657b2bd7ec2a772339716fa1c293c4352a709fdc71043d2265ade855d2a
|
||||
|
|
@ -852,15 +852,6 @@ RETURN NEW;
|
|||
END
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION trigger_b2d852e1e2cb() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
NEW."id_convert_to_bigint" := NEW."id";
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION trigger_b4520c29ea74() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
|
|
@ -6845,7 +6836,6 @@ CREATE SEQUENCE ci_pipeline_variables_id_seq
|
|||
ALTER SEQUENCE ci_pipeline_variables_id_seq OWNED BY p_ci_pipeline_variables.id;
|
||||
|
||||
CREATE TABLE ci_pipelines (
|
||||
id_convert_to_bigint integer DEFAULT 0 NOT NULL,
|
||||
ref character varying,
|
||||
sha character varying,
|
||||
before_sha character varying,
|
||||
|
|
@ -29927,8 +29917,6 @@ CREATE TRIGGER trigger_56d49f4ed623 BEFORE INSERT OR UPDATE ON workspace_variabl
|
|||
|
||||
CREATE TRIGGER trigger_94514aeadc50 BEFORE INSERT OR UPDATE ON deployment_approvals FOR EACH ROW EXECUTE FUNCTION trigger_94514aeadc50();
|
||||
|
||||
CREATE TRIGGER trigger_b2d852e1e2cb BEFORE INSERT OR UPDATE ON ci_pipelines FOR EACH ROW EXECUTE FUNCTION trigger_b2d852e1e2cb();
|
||||
|
||||
CREATE TRIGGER trigger_b4520c29ea74 BEFORE INSERT OR UPDATE ON approval_merge_request_rule_sources FOR EACH ROW EXECUTE FUNCTION trigger_b4520c29ea74();
|
||||
|
||||
CREATE TRIGGER trigger_catalog_resource_sync_event_on_project_update AFTER UPDATE ON projects FOR EACH ROW WHEN ((((old.name)::text IS DISTINCT FROM (new.name)::text) OR (old.description IS DISTINCT FROM new.description) OR (old.visibility_level IS DISTINCT FROM new.visibility_level))) EXECUTE FUNCTION insert_catalog_resource_sync_event();
|
||||
|
|
|
|||
|
|
@ -894,7 +894,7 @@ Parameters for all comments:
|
|||
| `position[start_sha]` | string | yes (if `position*` is supplied) | SHA referencing commit in target branch. |
|
||||
| `position[new_path]` | string | yes (if the position type is `text`) | File path after change. |
|
||||
| `position[old_path]` | string | yes (if the position type is `text`) | File path before change. |
|
||||
| `position[position_type]` | string | yes (if position* is supplied) | Type of the position reference. Allowed values: `text` or `image`. |
|
||||
| `position[position_type]` | string | yes (if position* is supplied) | Type of the position reference. Allowed values: `text`, `image`, or `file`. `file` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/423046) in GitLab 16.4. |
|
||||
| `commit_id` | string | no | SHA referencing commit to start this thread on. |
|
||||
| `created_at` | string | no | Date time string, ISO 8601 formatted, such as `2016-03-11T03:45:40Z`. Requires administrator or project/group owner rights. |
|
||||
| `position` | hash | no | Position when creating a diff note. |
|
||||
|
|
@ -1303,7 +1303,7 @@ Parameters:
|
|||
| `position[base_sha]` | string | yes (if `position*` is supplied) | SHA of the parent commit. |
|
||||
| `position[head_sha]` | string | yes (if `position*` is supplied) | The SHA of this commit. Same as `commit_id`. |
|
||||
| `position[start_sha]` | string | yes (if `position*` is supplied) | SHA of the parent commit. |
|
||||
| `position[position_type]` | string | yes (if `position*` is supplied) | Type of the position reference. Allowed values: `text` or `image`. |
|
||||
| `position[position_type]` | string | yes (if `position*` is supplied) | Type of the position reference. Allowed values: `text`, `image`, or `file`. `file` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/423046) in GitLab 16.4. |
|
||||
| `created_at` | string | no | Date time string, ISO 8601 formatted, such as `2016-03-11T03:45:40Z`. Requires administrator or project/group owner rights. |
|
||||
| `position` | hash | no | Position when creating a diff note. |
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/draft_notes
|
|||
| `position[start_sha]` | string | yes | SHA referencing commit in target branch. |
|
||||
| `position[new_path]` | string | yes (if the position type is `text`) | File path after change. |
|
||||
| `position[old_path]` | string | yes (if the position type is `text`) | File path before change. |
|
||||
| `position[position_type]` | string | yes | Type of the position reference. Allowed values: `text` or `image`. |
|
||||
| `position[position_type]` | string | yes | Type of the position reference. Allowed values: `text`, `image`, or `file`. `file` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/423046) in GitLab 16.4. |
|
||||
| `position` | hash | no | Position when creating a diff note. |
|
||||
| `position[new_line]` | integer | no | For `text` diff notes, the line number after change. |
|
||||
| `position[old_line]` | integer | no | For `text` diff notes, the line number before change. |
|
||||
|
|
@ -160,7 +160,7 @@ PUT /projects/:id/merge_requests/:merge_request_iid/draft_notes/:draft_note_id
|
|||
| `position[start_sha]` | string | yes | SHA referencing commit in target branch. |
|
||||
| `position[new_path]` | string | yes (if the position type is `text`) | File path after change. |
|
||||
| `position[old_path]` | string | yes (if the position type is `text`) | File path before change. |
|
||||
| `position[position_type]` | string | yes | Type of the position reference. Allowed values: `text` or `image`. |
|
||||
| `position[position_type]` | string | yes | Type of the position reference. Allowed values: `text`, `image` or `file`. `file` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/423046) in GitLab 16.4. |
|
||||
| `position` | hash | no | Position when creating a diff note. |
|
||||
| `position[new_line]` | integer | no | For `text` diff notes, the line number after change. |
|
||||
| `position[old_line]` | integer | no | For `text` diff notes, the line number before change. |
|
||||
|
|
|
|||
|
|
@ -27712,6 +27712,7 @@ paths:
|
|||
enum:
|
||||
- text
|
||||
- image
|
||||
- file
|
||||
required: true
|
||||
- in: formData
|
||||
name: position[new_path]
|
||||
|
|
@ -27906,6 +27907,7 @@ paths:
|
|||
enum:
|
||||
- text
|
||||
- image
|
||||
- file
|
||||
required: true
|
||||
- in: formData
|
||||
name: position[new_path]
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ For error tracking to work, you need:
|
|||
- To use the GitLab backend, see [GitLab Integrated error tracking](integrated_error_tracking.md).
|
||||
Integrated error tracking is available only on GitLab.com.
|
||||
- To use Sentry as the backend, see [Sentry based](sentry_error_tracking.md).
|
||||
Sentry based error tracking is available only for self-managed instances.
|
||||
Sentry based error tracking is available for GitLab.com, GitLab Dedicated and Self-managed instances.
|
||||
|
||||
Here is a summary of the capabilities for each version:
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** Self-managed, GitLab Dedicated
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
[Sentry](https://sentry.io/) is an open source error tracking system. GitLab enables
|
||||
administrators to connect Sentry to GitLab, so users can view a list of Sentry errors in GitLab.
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ You can use the [project access tokens API](../api/project_access_tokens.md) to
|
|||
programmatically take action, such as
|
||||
[rotating a project access token](../api/project_access_tokens.md#rotate-a-project-access-token).
|
||||
|
||||
Project owners and maintainers receive an email when project access tokens are 7 days or less from expiration.
|
||||
Project maintainers receive an email when project access tokens are 7 days or less from expiration.
|
||||
|
||||
## Group access tokens
|
||||
|
||||
|
|
|
|||
|
|
@ -154,11 +154,15 @@ If multiple topics are provided, all topics must match for the project to be inc
|
|||
|
||||
### AI Impact analytics
|
||||
|
||||
DETAILS:
|
||||
**Offering:** GitLab.com, Self-managed
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/443696) in GitLab 16.11 [with a flag](../../administration/feature_flags.md) named `ai_impact_analytics_dashboard`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `ai_impact_analytics_dashboard`.
|
||||
On GitLab.com and GitLab Dedicated, this feature is available.
|
||||
On GitLab.com this feature is available.
|
||||
On GitLab Dedicated this feature is not available.
|
||||
|
||||
AI Impact analytics displays SDLC metrics for a group or project in the month-to-date and the past six months. You can use this table to observe how changes in the AI usage metric correlate with changes in other metrics.
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ DETAILS:
|
|||
**Tier:** Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/367093) to the [Registration Features Program](../../../administration/settings/usage_statistics.md#registration-features-program) in GitLab 16.6.
|
||||
|
||||
DevOps Adoption shows you how groups in your organization adopt and use the most essential features of GitLab.
|
||||
|
||||
You can use Group DevOps Adoption to:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@ DETAILS:
|
|||
FLAG:
|
||||
The availability of this feature is controlled by feature flags. For more information, see the history.
|
||||
|
||||
The product analytics feature empowers you to track user behavior and gain insights into how your
|
||||
applications are used and how users interact with your product.
|
||||
By using the data collected with product analytics in GitLab, you can better understand your users,
|
||||
identify friction points in funnels, make data-driven product decisions, and ultimately build better
|
||||
products that drive user engagement and business growth.
|
||||
|
||||
For more information about the vision and development of product analytics, see the [group direction page](https://about.gitlab.com/direction/monitor/product-analytics/).
|
||||
To leave feedback about product analytics bugs or functionality:
|
||||
|
||||
|
|
|
|||
|
|
@ -356,13 +356,24 @@ You can disable following and being followed by other users.
|
|||
NOTE:
|
||||
When this feature is being disabled, all current followed/following connections are deleted.
|
||||
|
||||
## Advanced code search with zoekt
|
||||
## Exact code search
|
||||
|
||||
### Disable searching code with Zoekt
|
||||
### Enable exact code search
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/388519) as a beta feature [with a flag](../feature_flags.md) named `search_code_with_zoekt`. Enabled by default.
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed
|
||||
**Status:** Beta
|
||||
|
||||
You can disable searching with Zoekt and use Elasticsearch instead.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105049) as a [Beta](../../policy/experiment-beta-support.md#beta) in GitLab 15.9 [with flags](../../administration/feature_flags.md) named `index_code_with_zoekt` and `search_code_with_zoekt`. Disabled by default.
|
||||
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/388519) in GitLab 16.6.
|
||||
> - Feature flags `index_code_with_zoekt` and `search_code_with_zoekt` [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148378) in GitLab 17.1.
|
||||
|
||||
WARNING:
|
||||
This feature is in [Beta](../../policy/experiment-beta-support.md#beta) and subject to change without notice.
|
||||
For more information, see [epic 9404](https://gitlab.com/groups/gitlab-org/-/epics/9404).
|
||||
|
||||
To enable exact code search in GitLab:
|
||||
|
||||
1. On the left sidebar, select your avatar.
|
||||
1. Select **Edit profile**.
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ To add a merge request approval rule:
|
|||
1. Select **Settings > Merge requests**.
|
||||
1. In the **Merge request approvals** section, in the **Approval rules** section, select
|
||||
**Add approval rule**.
|
||||
1. Complete the fields:
|
||||
1. On the right sidebar, complete the fields:
|
||||
- In **Approvals required**, a value of `0` makes
|
||||
[the rule optional](#configure-optional-approval-rules), and any number greater than `0`
|
||||
creates a required rule.
|
||||
|
|
@ -57,7 +57,7 @@ To add a merge request approval rule:
|
|||
- From **Add approvers**, select users or groups that are
|
||||
[eligible to approve](#eligible-approvers).
|
||||
GitLab suggests approvers based on previous authors of the files changed by the merge request.
|
||||
1. Select **Add approval rule**. You can add [multiple approval rules](#multiple-approval-rules).
|
||||
1. Select **Save changes**. You can add [multiple approval rules](#multiple-approval-rules).
|
||||
|
||||
Your configuration for approval rule overrides determines if the new rule is applied
|
||||
to existing merge requests:
|
||||
|
|
@ -83,14 +83,14 @@ To edit a merge request approval rule:
|
|||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Settings > Merge requests**.
|
||||
1. In the **Merge request approvals** section, in the **Approval rules** section, next to the rule you want to edit, select **Edit**.
|
||||
1. Edit the fields:
|
||||
1. On the right sidebar, edit the fields:
|
||||
- In **Approvals required**, a value of `0` makes
|
||||
[the rule optional](#configure-optional-approval-rules), and any number greater than `0`
|
||||
creates a required rule.
|
||||
Maximum number of required approvals is `100`.
|
||||
- To remove users or groups, identify the group or user to remove, and select **Remove**
|
||||
(**{remove}**).
|
||||
1. Select **Update approval rule**.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Delete an approval rule
|
||||
|
||||
|
|
@ -213,8 +213,8 @@ To enable approval permissions for these users without granting them push access
|
|||
1. In the **Merge request approvals** section, in the **Approval rules** section:
|
||||
- For a new rule, select **Add approval rule** and target the protected branch.
|
||||
- For an existing rule, select **Edit** and target the protected branch.
|
||||
1. In **Add approvers**, select the group you created.
|
||||
1. Select **Add approval rule** or **Update approval rule**.
|
||||
1. On the right sidebar, in **Add approvers**, select the group you created.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Edit or override merge request approval rules
|
||||
|
||||
|
|
@ -302,21 +302,6 @@ on the merge request to indicate which steps are needed to proceed.
|
|||
|
||||
These policies are both created and edited in the [security policy editor](../../../application_security/policies/index.md#policy-editor).
|
||||
|
||||
## Edit approval rules in a drawer
|
||||
|
||||
DETAILS:
|
||||
**Status:** Beta
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/439397) in GitLab 16.11 [with a flag](../../../../administration/feature_flags.md) named `approval_rules_drawer`. Enabled by default. This feature is in [beta](../../../../policy/experiment-beta-support.md).
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is available.
|
||||
To hide the feature, an administrator can [disable the feature flag](../../../../administration/feature_flags.md) named `approval_rules_drawer`.
|
||||
On GitLab.com and GitLab Dedicated, this feature is available.
|
||||
|
||||
When this feature is enabled, the dialog to [add](#add-an-approval-rule) or
|
||||
[edit an approval](#edit-an-approval-rule) rule opens in a drawer on the right.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Approval rule name can't be blank
|
||||
|
|
|
|||
|
|
@ -11,12 +11,9 @@ DETAILS:
|
|||
**Offering:** GitLab.com, Self-managed
|
||||
**Status:** Beta
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105049) in GitLab 15.9 [with flags](../../administration/feature_flags.md) named `index_code_with_zoekt` and `search_code_with_zoekt`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
This feature is available for testing, but not ready for production use.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105049) as a [Beta](../../policy/experiment-beta-support.md#beta) in GitLab 15.9 [with flags](../../administration/feature_flags.md) named `index_code_with_zoekt` and `search_code_with_zoekt`. Disabled by default.
|
||||
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/388519) in GitLab 16.6.
|
||||
> - Feature flags `index_code_with_zoekt` and `search_code_with_zoekt` [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148378) in GitLab 17.1.
|
||||
|
||||
WARNING:
|
||||
This feature is in [beta](../../policy/experiment-beta-support.md#beta) and subject to change without notice.
|
||||
|
|
|
|||
|
|
@ -136,15 +136,15 @@ module API
|
|||
strong_memoize_attr :project
|
||||
|
||||
def package
|
||||
project.packages
|
||||
.conan
|
||||
.with_name(params[:package_name])
|
||||
.with_version(params[:package_version])
|
||||
.with_conan_username(params[:package_username])
|
||||
.with_conan_channel(params[:package_channel])
|
||||
.order_created
|
||||
.not_pending_destruction
|
||||
.last
|
||||
::Packages::Conan::Package
|
||||
.for_projects(project)
|
||||
.with_name(params[:package_name])
|
||||
.with_version(params[:package_version])
|
||||
.with_conan_username(params[:package_username])
|
||||
.with_conan_channel(params[:package_channel])
|
||||
.order_created
|
||||
.not_pending_destruction
|
||||
.last
|
||||
end
|
||||
strong_memoize_attr :package
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module Gitlab
|
|||
class Zoekt < Base
|
||||
override :should_pause?
|
||||
def should_pause?
|
||||
::Feature.enabled?(:zoekt_pause_indexing, type: :ops)
|
||||
Gitlab::CurrentSettings.zoekt_indexing_paused?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13690,6 +13690,9 @@ msgstr ""
|
|||
msgid "Configure settings for Advanced Search with Elasticsearch."
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure settings for exact code search."
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure specific limits for Files API requests that supersede the general user and IP rate limits."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13979,6 +13982,9 @@ msgstr ""
|
|||
msgid "ContainerRegistry|Copy push command"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Could not load signature details."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Created %{time}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -14137,6 +14143,9 @@ msgstr ""
|
|||
msgid "ContainerRegistry|Show full path"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Signature details"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Signature digest: %{digest}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -21124,6 +21133,9 @@ msgstr ""
|
|||
msgid "Evidence collection"
|
||||
msgstr ""
|
||||
|
||||
msgid "Exact code search"
|
||||
msgstr ""
|
||||
|
||||
msgid "Exactly one of %{attributes} is required"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -21610,7 +21622,7 @@ msgstr ""
|
|||
msgid "Failed to load branches. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to load deploy keys."
|
||||
msgid "Failed to load data."
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to load error details from Sentry."
|
||||
|
|
@ -21622,9 +21634,6 @@ msgstr ""
|
|||
msgid "Failed to load group activity metrics. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to load groups, users and deploy keys."
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to load groups."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -39169,7 +39178,7 @@ msgstr ""
|
|||
msgid "ProductAnalytics|3. Initiate the tracking"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProductAnalytics|A deployed instance of the analytics-stack project."
|
||||
msgid "ProductAnalytics|A deployed instance of the %{linkStart}helm-charts%{linkEnd} project."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProductAnalytics|Add another dimension"
|
||||
|
|
@ -55553,9 +55562,6 @@ msgstr ""
|
|||
msgid "Update appearance settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update approval rule"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update approvers"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@
|
|||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/fonts": "^1.3.0",
|
||||
"@gitlab/svgs": "3.99.0",
|
||||
"@gitlab/ui": "80.8.1",
|
||||
"@gitlab/ui": "80.10.0",
|
||||
"@gitlab/web-ide": "^0.0.1-dev-20240508140740",
|
||||
"@mattiasbuelens/web-streams-adapter": "^0.1.0",
|
||||
"@rails/actioncable": "7.0.8-1",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ gem 'capybara', '~> 3.40.0'
|
|||
gem 'capybara-screenshot', '~> 1.0.26'
|
||||
gem 'rake', '~> 13', '>= 13.2.1'
|
||||
gem 'rspec', '~> 3.13'
|
||||
gem 'selenium-webdriver', '= 4.20.1'
|
||||
gem 'selenium-webdriver', '= 4.21.0'
|
||||
gem 'airborne', '~> 0.3.7', require: false # airborne is messing with rspec sandboxed mode so not requiring by default
|
||||
gem 'rest-client', '~> 2.1.0'
|
||||
gem 'rspec_junit_formatter', '~> 0.6.0'
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ GEM
|
|||
sawyer (0.9.2)
|
||||
addressable (>= 2.3.5)
|
||||
faraday (>= 0.17.3, < 3)
|
||||
selenium-webdriver (4.20.1)
|
||||
selenium-webdriver (4.21.0)
|
||||
base64 (~> 0.2)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
rubyzip (>= 1.2.2, < 3.0)
|
||||
|
|
@ -395,7 +395,7 @@ DEPENDENCIES
|
|||
rspec-parameterized (~> 1.0.2)
|
||||
rspec_junit_formatter (~> 0.6.0)
|
||||
ruby-debug-ide (~> 0.7.3)
|
||||
selenium-webdriver (= 4.20.1)
|
||||
selenium-webdriver (= 4.21.0)
|
||||
slack-notifier (~> 2.4)
|
||||
terminal-table (~> 3.0.2)
|
||||
warning (~> 1.3)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :conan_package, class: 'Packages::Conan::Package', parent: :package do
|
||||
package_type { :conan }
|
||||
sequence(:name) { |n| "package-#{n}" }
|
||||
version { '1.0.0' }
|
||||
|
||||
conan_metadatum
|
||||
|
||||
transient do
|
||||
without_package_files { false }
|
||||
end
|
||||
|
||||
after :build do |package|
|
||||
package.conan_metadatum.package_username = ::Packages::Conan::Metadatum.package_username_from(
|
||||
full_path: package.project.full_path
|
||||
)
|
||||
end
|
||||
|
||||
after :create do |package, evaluator|
|
||||
unless evaluator.without_package_files
|
||||
%i[conan_recipe_file conan_recipe_manifest conan_package_info conan_package_manifest
|
||||
conan_package].each do |file|
|
||||
create :conan_package_file, file, package: package
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
trait(:without_loaded_metadatum) do
|
||||
conan_metadatum { association(:conan_metadatum, package: nil, strategy: :build) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -252,38 +252,6 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
factory :conan_package do
|
||||
conan_metadatum
|
||||
|
||||
transient do
|
||||
without_package_files { false }
|
||||
end
|
||||
|
||||
after :build do |package|
|
||||
package.conan_metadatum.package_username = Packages::Conan::Metadatum.package_username_from(
|
||||
full_path: package.project.full_path
|
||||
)
|
||||
end
|
||||
|
||||
sequence(:name) { |n| "package-#{n}" }
|
||||
version { '1.0.0' }
|
||||
package_type { :conan }
|
||||
|
||||
after :create do |package, evaluator|
|
||||
unless evaluator.without_package_files
|
||||
create :conan_package_file, :conan_recipe_file, package: package
|
||||
create :conan_package_file, :conan_recipe_manifest, package: package
|
||||
create :conan_package_file, :conan_package_info, package: package
|
||||
create :conan_package_file, :conan_package_manifest, package: package
|
||||
create :conan_package_file, :conan_package, package: package
|
||||
end
|
||||
end
|
||||
|
||||
trait(:without_loaded_metadatum) do
|
||||
conan_metadatum { build(:conan_metadatum, package: nil) } # rubocop:disable RSpec/FactoryBot/InlineAssociation
|
||||
end
|
||||
end
|
||||
|
||||
factory :generic_package do
|
||||
sequence(:name) { |n| "generic-package-#{n}" }
|
||||
version { '1.0.0' }
|
||||
|
|
|
|||
|
|
@ -6,57 +6,116 @@ RSpec.describe 'User comments on a diff with whitespace changes', :js, feature_c
|
|||
include MergeRequestDiffHelpers
|
||||
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let(:merge_request) do
|
||||
create(:merge_request_with_diffs, source_project: project, target_project: project,
|
||||
source_branch: 'changes-with-whitespace')
|
||||
end
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
|
||||
visit(diffs_project_merge_request_path(project, merge_request, view: 'parallel'))
|
||||
end
|
||||
|
||||
context 'when hiding whitespace changes' do
|
||||
context 'when MR contains a whitespace diff which contains line combinations that are not present in the real diff' do
|
||||
let(:merge_request) do
|
||||
create(:merge_request_with_diffs, source_project: project, target_project: project,
|
||||
source_branch: 'changes-with-whitespace')
|
||||
end
|
||||
|
||||
before do
|
||||
find('.js-show-diff-settings').click
|
||||
find_by_testid('show-whitespace').click
|
||||
wait_for_requests
|
||||
visit(diffs_project_merge_request_path(project, merge_request, view: 'parallel'))
|
||||
end
|
||||
|
||||
context 'when commenting on line combinations that are not present in the real diff' do
|
||||
context 'when hiding whitespace changes' do
|
||||
before do
|
||||
# Comment on line combination old: 19, new 20
|
||||
# This line combination does not exist when whitespace is shown
|
||||
click_diff_line(
|
||||
find_by_scrolling('div[data-path="files/ruby/popen.rb"] .left-side a[data-linenumber="19"]').find(:xpath,
|
||||
'../..'), 'left')
|
||||
page.within('.js-discussion-note-form') do
|
||||
fill_in(:note_note, with: 'Comment on diff with whitespace')
|
||||
hide_whitespace
|
||||
end
|
||||
|
||||
context 'when commenting on line combinations that are not present in the real diff' do
|
||||
before do
|
||||
# Comment on line combination old: 19, new 20
|
||||
# This line combination does not exist when whitespace is shown
|
||||
click_diff_line(
|
||||
find_by_scrolling('div[data-path="files/ruby/popen.rb"] .left-side a[data-linenumber="19"]').find(:xpath,
|
||||
'../..'), 'left')
|
||||
page.within('.js-discussion-note-form') do
|
||||
fill_in(:note_note, with: 'Comment on diff with whitespace')
|
||||
click_button('Add comment now')
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it 'shows the comments in the diff' do
|
||||
page.within('.notes_holder') do
|
||||
expect(page).to have_content('Comment on diff with whitespace')
|
||||
end
|
||||
end
|
||||
|
||||
it 'allows replies to comments in the diff' do
|
||||
click_button('Reply to comment')
|
||||
fill_in(:note_note, with: 'reply to whitespace comment')
|
||||
click_button('Add comment now')
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it 'shows the comments in the diff' do
|
||||
page.within('.notes_holder') do
|
||||
expect(page).to have_content('Comment on diff with whitespace')
|
||||
end
|
||||
end
|
||||
|
||||
it 'allows replies to comments in the diff' do
|
||||
click_button('Reply to comment')
|
||||
fill_in(:note_note, with: 'reply to whitespace comment')
|
||||
click_button('Add comment now')
|
||||
wait_for_requests
|
||||
page.within('.notes_holder') do
|
||||
expect(page).to have_content('reply to whitespace comment')
|
||||
wait_for_requests
|
||||
page.within('.notes_holder') do
|
||||
expect(page).to have_content('reply to whitespace comment')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the MR contains a diff with a file with whitespace changes only' do
|
||||
let(:merge_request) do
|
||||
create(:merge_request_with_diffs, source_project: project, target_project: project, target_branch: 'master',
|
||||
source_branch: 'changes-with-only-whitespace')
|
||||
end
|
||||
|
||||
before do
|
||||
visit(diffs_project_merge_request_path(project, merge_request, view: 'parallel'))
|
||||
end
|
||||
|
||||
context 'when hiding whitespace changes' do
|
||||
before do
|
||||
hide_whitespace
|
||||
end
|
||||
|
||||
context 'when showing changes and commenting' do
|
||||
before do
|
||||
click_button('Show changes')
|
||||
wait_for_requests
|
||||
|
||||
click_diff_line(
|
||||
find_by_scrolling('div[data-path="files/ruby/popen.rb"] .left-side a[data-linenumber="1"]').find(:xpath,
|
||||
'../..'), 'left')
|
||||
page.within('.js-discussion-note-form') do
|
||||
fill_in(:note_note, with: 'Comment on whitespace only diff')
|
||||
click_button('Add comment now')
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it 'shows the comments in the diff' do
|
||||
page.within('.notes_holder') do
|
||||
expect(page).to have_content('Comment on whitespace only diff')
|
||||
end
|
||||
end
|
||||
|
||||
it 'allows replies to comments in the diff' do
|
||||
click_button('Reply to comment')
|
||||
fill_in(:note_note, with: 'reply to whitespace only comment')
|
||||
click_button('Add comment now')
|
||||
wait_for_requests
|
||||
page.within('.notes_holder') do
|
||||
expect(page).to have_content('reply to whitespace only comment')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def hide_whitespace
|
||||
find('.js-show-diff-settings').click
|
||||
find_by_testid('show-whitespace').click
|
||||
wait_for_requests
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -88,112 +88,17 @@ RSpec.describe 'Protected Branches', :js, feature_category: :source_code_managem
|
|||
enable_admin_mode!(admin)
|
||||
end
|
||||
|
||||
describe "explicit protected branches" do
|
||||
it "allows creating explicit protected branches" do
|
||||
visit project_protected_branches_path(project)
|
||||
it_behaves_like 'setting project protected branches'
|
||||
|
||||
show_add_form
|
||||
set_defaults
|
||||
set_protected_branch_name('some->branch')
|
||||
click_on "Protect"
|
||||
it "shows success alert once protected branch is created" do
|
||||
visit project_protected_branches_path(project)
|
||||
|
||||
within(".protected-branches-list") { expect(page).to have_content('some->branch') }
|
||||
expect(ProtectedBranch.count).to eq(1)
|
||||
expect(ProtectedBranch.last.name).to eq('some->branch')
|
||||
end
|
||||
|
||||
it "shows success alert once protected branch is created" do
|
||||
visit project_protected_branches_path(project)
|
||||
|
||||
show_add_form
|
||||
set_defaults
|
||||
set_protected_branch_name('some->branch')
|
||||
click_on "Protect"
|
||||
wait_for_requests
|
||||
expect(page).to have_content(s_('ProtectedBranch|View protected branches as branch rules'))
|
||||
end
|
||||
|
||||
it "displays the last commit on the matching branch if it exists" do
|
||||
commit = create(:commit, project: project)
|
||||
project.repository.add_branch(admin, 'some-branch', commit.id)
|
||||
|
||||
visit project_protected_branches_path(project)
|
||||
|
||||
show_add_form
|
||||
set_defaults
|
||||
set_protected_branch_name('some-branch')
|
||||
click_on "Protect"
|
||||
|
||||
within(".protected-branches-list") do
|
||||
expect(page).not_to have_content("matching")
|
||||
expect(page).not_to have_content("was deleted")
|
||||
end
|
||||
end
|
||||
|
||||
it "displays an error message if the named branch does not exist" do
|
||||
visit project_protected_branches_path(project)
|
||||
|
||||
show_add_form
|
||||
set_defaults
|
||||
set_protected_branch_name('some-branch')
|
||||
click_on "Protect"
|
||||
|
||||
within(".protected-branches-list") { expect(page).to have_content('Branch does not exist') }
|
||||
end
|
||||
end
|
||||
|
||||
describe "wildcard protected branches" do
|
||||
it "allows creating protected branches with a wildcard" do
|
||||
visit project_protected_branches_path(project)
|
||||
|
||||
show_add_form
|
||||
set_defaults
|
||||
set_protected_branch_name('*-stable')
|
||||
click_on "Protect"
|
||||
|
||||
within(".protected-branches-list") { expect(page).to have_content('*-stable') }
|
||||
expect(ProtectedBranch.count).to eq(1)
|
||||
expect(ProtectedBranch.last.name).to eq('*-stable')
|
||||
end
|
||||
|
||||
it "displays the number of matching branches",
|
||||
quarantine: 'https://gitlab.com/gitlab-org/quality/engineering-productivity/flaky-tests/-/issues/3459' do
|
||||
project.repository.add_branch(admin, 'production-stable', 'master')
|
||||
project.repository.add_branch(admin, 'staging-stable', 'master')
|
||||
|
||||
visit project_protected_branches_path(project)
|
||||
|
||||
show_add_form
|
||||
set_defaults
|
||||
set_protected_branch_name('*-stable')
|
||||
click_on "Protect"
|
||||
|
||||
within(".protected-branches-list") do
|
||||
expect(page).to have_content("2 matching branches")
|
||||
end
|
||||
end
|
||||
|
||||
it "displays all the branches matching the wildcard" do
|
||||
project.repository.add_branch(admin, 'production-stable', 'master')
|
||||
project.repository.add_branch(admin, 'staging-stable', 'master')
|
||||
project.repository.add_branch(admin, 'development', 'master')
|
||||
|
||||
visit project_protected_branches_path(project)
|
||||
|
||||
show_add_form
|
||||
set_protected_branch_name('*-stable')
|
||||
set_defaults
|
||||
click_on "Protect"
|
||||
|
||||
visit project_protected_branches_path(project)
|
||||
click_on "2 matching branches"
|
||||
|
||||
within(".protected-branches-list") do
|
||||
expect(page).to have_content("production-stable")
|
||||
expect(page).to have_content("staging-stable")
|
||||
expect(page).not_to have_content("development")
|
||||
end
|
||||
end
|
||||
show_add_form
|
||||
set_defaults
|
||||
set_protected_branch_name('some->branch')
|
||||
click_on "Protect"
|
||||
wait_for_requests
|
||||
expect(page).to have_content(s_('ProtectedBranch|View protected branches as branch rules'))
|
||||
end
|
||||
|
||||
describe "access control" do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
import VueApollo from 'vue-apollo';
|
||||
import Vue from 'vue';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlLoadingIcon, GlModal, GlAlert } from '@gitlab/ui';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import SignatureDetailsModal from '~/packages_and_registries/container_registry/explorer/components/details_page/signature_details_modal.vue';
|
||||
import getManifestDetailsQuery from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_manifest_details.query.graphql';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { __ } from '~/locale';
|
||||
import CodeBlockHighlighted from '~/vue_shared/components/code_block_highlighted.vue';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
describe('Signature details modal', () => {
|
||||
let wrapper;
|
||||
|
||||
const defaultManifestDetailsHandler = jest
|
||||
.fn()
|
||||
.mockResolvedValue({ data: { containerRepository: { id: 1, manifest: 'manifest details' } } });
|
||||
|
||||
const createWrapper = ({
|
||||
manifestDetailsHandler = defaultManifestDetailsHandler,
|
||||
visible = true,
|
||||
digest = 'sha256:abcdef',
|
||||
} = {}) => {
|
||||
wrapper = shallowMount(SignatureDetailsModal, {
|
||||
propsData: { visible, digest },
|
||||
apolloProvider: createMockApollo([[getManifestDetailsQuery, manifestDetailsHandler]]),
|
||||
mocks: { $route: { params: { id: 123 } } },
|
||||
});
|
||||
|
||||
return waitForPromises();
|
||||
};
|
||||
|
||||
const findModal = () => wrapper.findComponent(GlModal);
|
||||
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findCodeBlockHighlighted = () => wrapper.findComponent(CodeBlockHighlighted);
|
||||
|
||||
describe('modal', () => {
|
||||
it('shows modal with expected settings', () => {
|
||||
createWrapper();
|
||||
|
||||
expect(findModal().attributes()).toHaveProperty('scrollable');
|
||||
expect(findModal().props()).toMatchObject({
|
||||
title: 'Signature details',
|
||||
actionCancel: { text: __('Close') },
|
||||
});
|
||||
});
|
||||
|
||||
it.each([true, false])('passes %s visible prop', (visible) => {
|
||||
createWrapper({ visible });
|
||||
|
||||
expect(findModal().props('visible')).toBe(visible);
|
||||
});
|
||||
|
||||
it('emits close event when modal is closed', () => {
|
||||
createWrapper();
|
||||
findModal().vm.$emit('hidden');
|
||||
|
||||
expect(wrapper.emitted('close')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('manifest details query', () => {
|
||||
it('calls query with expected variables', () => {
|
||||
createWrapper();
|
||||
|
||||
expect(defaultManifestDetailsHandler).toHaveBeenCalledTimes(1);
|
||||
expect(defaultManifestDetailsHandler).toHaveBeenCalledWith({
|
||||
id: 'gid://gitlab/ContainerRepository/123',
|
||||
reference: 'sha256:abcdef',
|
||||
});
|
||||
});
|
||||
|
||||
it('does not call query when there is no digest', () => {
|
||||
createWrapper({ digest: null });
|
||||
|
||||
expect(defaultManifestDetailsHandler).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when query is loading', () => {
|
||||
beforeEach(() => {
|
||||
createWrapper();
|
||||
});
|
||||
|
||||
it('shows loading icon', () => {
|
||||
expect(findLoadingIcon().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not show error alert', () => {
|
||||
expect(findAlert().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not show code block', () => {
|
||||
expect(findCodeBlockHighlighted().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when query encounters an error', () => {
|
||||
beforeEach(() => {
|
||||
return createWrapper({ manifestDetailsHandler: jest.fn().mockRejectedValue() });
|
||||
});
|
||||
|
||||
it('does not show loading icon', () => {
|
||||
expect(findLoadingIcon().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('shows error alert with expected props and text', () => {
|
||||
expect(findAlert().props()).toMatchObject({
|
||||
variant: 'danger',
|
||||
dismissible: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('shows error alert with expected text', () => {
|
||||
expect(findAlert().text()).toBe('Could not load signature details.');
|
||||
});
|
||||
|
||||
it('does not show code block', () => {
|
||||
expect(findCodeBlockHighlighted().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when query finishes loading', () => {
|
||||
beforeEach(() => {
|
||||
return createWrapper();
|
||||
});
|
||||
|
||||
it('does not show loading icon', () => {
|
||||
expect(findLoadingIcon().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not show error alert', () => {
|
||||
expect(findAlert().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('shows code block with expected props', () => {
|
||||
expect(findCodeBlockHighlighted().props()).toMatchObject({
|
||||
language: 'json',
|
||||
code: 'manifest details',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -5,11 +5,13 @@ import {
|
|||
GlDisclosureDropdown,
|
||||
GlDisclosureDropdownItem,
|
||||
GlBadge,
|
||||
GlLink,
|
||||
} from '@gitlab/ui';
|
||||
import { nextTick } from 'vue';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import TagsListRow from '~/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue';
|
||||
import SignatureDetailsModal from '~/packages_and_registries/container_registry/explorer/components/details_page/signature_details_modal.vue';
|
||||
import {
|
||||
REMOVE_TAG_BUTTON_TITLE,
|
||||
MISSING_MANIFEST_WARNING_TOOLTIP,
|
||||
|
|
@ -45,6 +47,7 @@ describe('tags list row', () => {
|
|||
const findAdditionalActionsMenu = () => wrapper.findComponent(GlDisclosureDropdown);
|
||||
const findDeleteButton = () => wrapper.findComponent(GlDisclosureDropdownItem);
|
||||
const findSignedBadge = () => wrapper.findComponent(GlBadge);
|
||||
const findSignatureDetailsModal = () => wrapper.findComponent(SignatureDetailsModal);
|
||||
|
||||
const mountComponent = (propsData = defaultProps) => {
|
||||
wrapper = shallowMountExtended(TagsListRow, {
|
||||
|
|
@ -437,6 +440,10 @@ describe('tags list row', () => {
|
|||
it('does not show the signature details row', () => {
|
||||
expect(findSignaturesDetails().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not show the signatures modal', () => {
|
||||
expect(findSignatureDetailsModal().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with signatures', () => {
|
||||
|
|
@ -485,6 +492,38 @@ describe('tags list row', () => {
|
|||
`Signature digest: sha256:${index}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('shows the view details link', () => {
|
||||
expect(findSignaturesDetails().at(index).findComponent(GlLink).text()).toBe(
|
||||
'View details',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('signature details modal', () => {
|
||||
it('does not show modal by default', () => {
|
||||
expect(findSignatureDetailsModal().props('visible')).toBe(false);
|
||||
expect(findSignatureDetailsModal().props('digest')).toBe(null);
|
||||
});
|
||||
|
||||
describe(`when a row's view details link is clicked`, () => {
|
||||
beforeEach(() => {
|
||||
findSignaturesDetails().at(0).findComponent(GlLink).vm.$emit('click');
|
||||
});
|
||||
|
||||
it('shows modal', () => {
|
||||
expect(findSignatureDetailsModal().props('visible')).toBe(true);
|
||||
expect(findSignatureDetailsModal().props('digest')).toBe('sha256:0');
|
||||
});
|
||||
|
||||
it('hides modal when the modal is closed', async () => {
|
||||
findSignatureDetailsModal().vm.$emit('close');
|
||||
await nextTick();
|
||||
|
||||
expect(findSignatureDetailsModal().props('visible')).toBe(false);
|
||||
expect(findSignatureDetailsModal().props('digest')).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -119,6 +119,19 @@ describe('Access Level Dropdown', () => {
|
|||
expect(getGroups).toHaveBeenCalledWith({ withProjectAccess: true });
|
||||
expect(getDeployKeys).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('with limit_repository_settings = protected_branches', () => {
|
||||
it('should not make an api call for depoloyKeys', () => {
|
||||
window.gon = {
|
||||
limit_repository_settings: ['protected_branches'],
|
||||
};
|
||||
|
||||
createComponent({ groupsWithProjectAccess: true });
|
||||
expect(getUsers).toHaveBeenCalled();
|
||||
expect(getGroups).toHaveBeenCalledWith({ withProjectAccess: true });
|
||||
expect(getDeployKeys).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should make an api call for deployKeys but not for users or groups when user does not have a license', () => {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe BulkImports::ObjectCounter, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe BulkImports::ObjectCounter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:tracker) { build(:bulk_import_tracker, id: non_existing_record_id) }
|
||||
let_it_be(:cache_key) { "bulk_imports/object_counter/#{tracker.id}" }
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ RSpec.describe BulkImports::Projects::Pipelines::SnippetsRepositoryPipeline, fea
|
|||
end
|
||||
end
|
||||
|
||||
describe '#run', :clean_gitlab_redis_cache do
|
||||
describe '#run', :clean_gitlab_redis_shared_state do
|
||||
let(:validation_response) { double(Hash, 'error?': false) }
|
||||
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::IssueImporter, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::IssueImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
include AfterNextHelpers
|
||||
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::IssueNotesImporter, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::IssueNotesImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:project) do
|
||||
create(:project, :import_started, import_source: 'namespace/repo',
|
||||
import_data_attributes: {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::IssuesImporter, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::IssuesImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:project) do
|
||||
create(:project, :import_started,
|
||||
import_data_attributes: {
|
||||
|
|
@ -29,7 +29,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::IssuesImporter, feature_categ
|
|||
|
||||
subject(:importer) { described_class.new(project) }
|
||||
|
||||
describe '#execute', :clean_gitlab_redis_cache do
|
||||
describe '#execute' do
|
||||
context 'when the repo does not have issue tracking enabled' do
|
||||
before do
|
||||
allow(client).to receive(:repo).and_return(Bitbucket::Representation::Repo.new({ 'has_issues' => false }))
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::IssuesNotesImporter, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::IssuesNotesImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:project) { create(:project, :import_started) }
|
||||
let_it_be(:issue_1) { create(:issue, project: project) }
|
||||
let_it_be(:issue_2) { create(:issue, project: project) }
|
||||
|
||||
subject(:importer) { described_class.new(project) }
|
||||
|
||||
describe '#execute', :clean_gitlab_redis_cache do
|
||||
describe '#execute' do
|
||||
it 'imports the notes from each issue in parallel' do
|
||||
expect(Gitlab::BitbucketImport::ImportIssueNotesWorker).to receive(:perform_in).twice
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::LfsObjectsImporter, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::LfsObjectsImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:project) do
|
||||
create(:project, :import_started,
|
||||
import_data_attributes: {
|
||||
|
|
@ -32,7 +32,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::LfsObjectsImporter, feature_c
|
|||
}
|
||||
end
|
||||
|
||||
describe '#execute', :clean_gitlab_redis_cache do
|
||||
describe '#execute' do
|
||||
context 'when lfs is enabled' do
|
||||
before do
|
||||
allow(project).to receive(:lfs_enabled?).and_return(true)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestImporter, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
include AfterNextHelpers
|
||||
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestNotesImporter, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestNotesImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:project) do
|
||||
create(:project, :repository, :import_started,
|
||||
import_data_attributes: {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsImporter, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:project) do
|
||||
create(:project, :import_started,
|
||||
import_data_attributes: {
|
||||
|
|
@ -14,7 +14,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsImporter, feature
|
|||
|
||||
subject(:importer) { described_class.new(project) }
|
||||
|
||||
describe '#execute', :clean_gitlab_redis_cache do
|
||||
describe '#execute' do
|
||||
before do
|
||||
allow_next_instance_of(Bitbucket::Client) do |client|
|
||||
allow(client).to receive(:pull_requests).and_return(
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsNotesImporter, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsNotesImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:project) { create(:project, :import_started) }
|
||||
let_it_be(:merge_request_1) { create(:merge_request, source_project: project) }
|
||||
let_it_be(:merge_request_2) { create(:merge_request, source_project: project, source_branch: 'other-branch') }
|
||||
|
||||
subject(:importer) { described_class.new(project) }
|
||||
|
||||
describe '#execute', :clean_gitlab_redis_cache do
|
||||
describe '#execute' do
|
||||
it 'imports the notes from each merge request in parallel' do
|
||||
expect(Gitlab::BitbucketImport::ImportPullRequestNotesWorker).to receive(:perform_in).twice
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketImport::UserFinder, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketImport::UserFinder, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:identity) { create(:identity, user: user, extern_uid: 'uid', provider: :bitbucket) }
|
||||
let(:created_id) { 1 }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketServerImport::Importers::LfsObjectsImporter, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketServerImport::Importers::LfsObjectsImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:project) do
|
||||
create(:project, :import_started,
|
||||
import_data_attributes: {
|
||||
|
|
@ -32,7 +32,7 @@ RSpec.describe Gitlab::BitbucketServerImport::Importers::LfsObjectsImporter, fea
|
|||
}
|
||||
end
|
||||
|
||||
describe '#execute', :clean_gitlab_redis_cache do
|
||||
describe '#execute' do
|
||||
context 'when lfs is enabled' do
|
||||
before do
|
||||
allow(project).to receive(:lfs_enabled?).and_return(true)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketServerImport::Importers::PullRequestsImporter, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketServerImport::Importers::PullRequestsImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
include RepoHelpers
|
||||
|
||||
let_it_be(:project) do
|
||||
|
|
@ -18,7 +18,7 @@ RSpec.describe Gitlab::BitbucketServerImport::Importers::PullRequestsImporter, f
|
|||
|
||||
subject(:importer) { described_class.new(project) }
|
||||
|
||||
describe '#execute', :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state do
|
||||
describe '#execute' do
|
||||
let(:commit_sha) { 'aaaa1' }
|
||||
|
||||
let(:page_hash_1) do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BitbucketServerImport::UserFinder, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::BitbucketServerImport::UserFinder, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:created_id) { 1 }
|
||||
|
|
|
|||
|
|
@ -1528,7 +1528,7 @@ RSpec.describe Gitlab::Git::Repository, feature_category: :source_code_managemen
|
|||
it "returns the number of commits in the whole repository" do
|
||||
options = { all: true }
|
||||
|
||||
expect(repository.count_commits(options)).to eq(322)
|
||||
expect(repository.count_commits(options)).to eq(323)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ RSpec.describe Gitlab::GithubImport::Clients::Proxy, :manage, feature_category:
|
|||
end
|
||||
end
|
||||
|
||||
describe '#count_by', :clean_gitlab_redis_cache do
|
||||
describe '#count_repos_by', :clean_gitlab_redis_shared_state do
|
||||
let(:client_stub) { instance_double(Gitlab::GithubImport::Client) }
|
||||
let(:client_response) { { data: { search: { repositoryCount: 1 } } } }
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Attachments::IssuesImporter, feat
|
|||
|
||||
let(:client) { instance_double(Gitlab::GithubImport::Client) }
|
||||
|
||||
describe '#sequential_import', :clean_gitlab_redis_cache do
|
||||
describe '#sequential_import', :clean_gitlab_redis_shared_state do
|
||||
let_it_be(:issue) { create(:issue, project: project) }
|
||||
|
||||
let_it_be(:issue_with_attachment) do
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Attachments::MergeRequestsImporte
|
|||
|
||||
let(:client) { instance_double(Gitlab::GithubImport::Client) }
|
||||
|
||||
describe '#sequential_import', :clean_gitlab_redis_cache do
|
||||
describe '#sequential_import', :clean_gitlab_redis_shared_state do
|
||||
let_it_be(:mr) { create(:merge_request, source_project: project, target_branch: 'feature1') }
|
||||
|
||||
let_it_be(:mr_with_attachment) do
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Attachments::NotesImporter, featu
|
|||
|
||||
let(:client) { instance_double(Gitlab::GithubImport::Client) }
|
||||
|
||||
describe '#sequential_import', :clean_gitlab_redis_cache do
|
||||
describe '#sequential_import', :clean_gitlab_redis_shared_state do
|
||||
let_it_be(:note) { create(:note, project: project) }
|
||||
|
||||
let_it_be(:note_with_attachment) do
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Attachments::ReleasesImporter, fe
|
|||
|
||||
let(:client) { instance_double(Gitlab::GithubImport::Client) }
|
||||
|
||||
describe '#sequential_import', :clean_gitlab_redis_cache do
|
||||
describe '#sequential_import', :clean_gitlab_redis_shared_state do
|
||||
let_it_be(:release) { create(:release, project: project) }
|
||||
|
||||
let_it_be(:release_with_attachment) do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
subject(:importer) { described_class.new(project, client) }
|
||||
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Importer::IssueEventImporter, :clean_gitlab_redis_cache,
|
||||
feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::Importer::IssueEventImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let(:importer) { described_class.new(issue_event, project, client) }
|
||||
|
||||
let(:project) { build(:project) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:work_item_type_id) { ::WorkItems::Type.default_issue_type.id }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Importer::LabelsImporter, :clean_gitlab_redis_cache,
|
||||
feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::Importer::LabelsImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let(:project) { create(:project, import_source: 'foo/bar') }
|
||||
let(:client) { double(:client) }
|
||||
let(:importer) { described_class.new(project, client) }
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Importer::MilestonesImporter, :clean_gitlab_redis_cache,
|
||||
feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::Importer::MilestonesImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let(:project) { create(:project, import_source: 'foo/bar') }
|
||||
let(:client) { double(:client) }
|
||||
let(:importer) { described_class.new(project, client) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:client) { double(:client) }
|
||||
let(:user) { create(:user) }
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Importer::PullRequests::MergedByImporter,
|
||||
:clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::Importer::PullRequests::MergedByImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:merge_request) { create(:merged_merge_request) }
|
||||
|
||||
let(:project) { merge_request.project }
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewImporter,
|
||||
:clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:merge_request) { create(:merge_request) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewRequestImporter, :clean_gitlab_redis_cache do
|
||||
RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewRequestImporter, :clean_gitlab_redis_shared_state do
|
||||
subject(:importer) { described_class.new(review_request, project, client) }
|
||||
|
||||
let(:project) { instance_double('Project') }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::IssuableFinder, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::IssuableFinder, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let(:project) { build(:project, id: 20, import_data_attributes: import_data_attributes) }
|
||||
let(:single_endpoint_optional_stage) { false }
|
||||
let(:import_data_attributes) do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::LabelFinder, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::LabelFinder, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:finder) { described_class.new(project) }
|
||||
let_it_be(:bug) { create(:label, project: project, name: 'Bug') }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::MilestoneFinder, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
RSpec.describe Gitlab::GithubImport::MilestoneFinder, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:milestone) { create(:milestone, project: project) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Representation::DiffNote, :clean_gitlab_redis_cache do
|
||||
RSpec.describe Gitlab::GithubImport::Representation::DiffNote do
|
||||
let(:hunk) do
|
||||
'@@ -1 +1 @@
|
||||
-Hello
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Representation::DiffNotes::DiscussionId, :clean_gitlab_redis_cache,
|
||||
RSpec.describe Gitlab::GithubImport::Representation::DiffNotes::DiscussionId, :clean_gitlab_redis_shared_state,
|
||||
feature_category: :importers do
|
||||
describe '#discussion_id' do
|
||||
let(:hunk) do
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ RSpec.describe Gitlab::JiraImport::BaseImporter do
|
|||
it { expect(subject.send(:imported_items_cache_key)).to eq('dumb-importer-key') }
|
||||
end
|
||||
|
||||
describe '#mark_as_imported', :clean_gitlab_redis_cache do
|
||||
describe '#mark_as_imported', :clean_gitlab_redis_shared_state do
|
||||
it 'stores id in redis cache' do
|
||||
expect(Gitlab::Cache::Import::Caching).to receive(:set_add).once.and_call_original
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ RSpec.describe Gitlab::JiraImport::BaseImporter do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#already_imported?', :clean_gitlab_redis_cache do
|
||||
describe '#already_imported?', :clean_gitlab_redis_shared_state do
|
||||
it 'returns false if value is not in cache' do
|
||||
expect(Gitlab::Cache::Import::Caching).to receive(:set_includes?).once.and_call_original
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::JiraImport::IssuesImporter do
|
||||
RSpec.describe Gitlab::JiraImport::IssuesImporter, :clean_gitlab_redis_shared_state do
|
||||
include JiraIntegrationHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
|
@ -23,7 +23,7 @@ RSpec.describe Gitlab::JiraImport::IssuesImporter do
|
|||
it { expect(subject.imported_items_cache_key).to eq("jira-importer/already-imported/#{project.id}/issues") }
|
||||
end
|
||||
|
||||
describe '#execute', :clean_gitlab_redis_cache do
|
||||
describe '#execute' do
|
||||
context 'when no returned issues' do
|
||||
it 'does not schedule any import jobs' do
|
||||
expect(subject).to receive(:fetch_issues).with(0).and_return([])
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::JiraImport::LabelsImporter do
|
||||
RSpec.describe Gitlab::JiraImport::LabelsImporter, :clean_gitlab_redis_shared_state do
|
||||
include JiraIntegrationHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
|
@ -18,7 +18,7 @@ RSpec.describe Gitlab::JiraImport::LabelsImporter do
|
|||
stub_const('Gitlab::JiraImport::LabelsImporter::MAX_LABELS', 2)
|
||||
end
|
||||
|
||||
describe '#execute', :clean_gitlab_redis_cache do
|
||||
describe '#execute' do
|
||||
before do
|
||||
stub_jira_integration_test
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::PauseControl::Client, :clean_gitlab_re
|
|||
describe '#call' do
|
||||
context 'when strategy is enabled' do
|
||||
before do
|
||||
stub_feature_flags(zoekt_pause_indexing: true)
|
||||
allow(Gitlab::CurrentSettings).to receive(:zoekt_indexing_paused?).and_return(true)
|
||||
end
|
||||
|
||||
it 'does not schedule the job' do
|
||||
|
|
@ -38,7 +38,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::PauseControl::Client, :clean_gitlab_re
|
|||
|
||||
context 'when strategy is disabled' do
|
||||
before do
|
||||
stub_feature_flags(zoekt_pause_indexing: false)
|
||||
allow(Gitlab::CurrentSettings).to receive(:zoekt_indexing_paused?).and_return(false)
|
||||
end
|
||||
|
||||
it 'schedules the job' do
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::PauseControl::Server, :clean_gitlab_re
|
|||
describe '#call' do
|
||||
context 'when strategy is enabled' do
|
||||
before do
|
||||
stub_feature_flags(zoekt_pause_indexing: true)
|
||||
allow(Gitlab::CurrentSettings).to receive(:zoekt_indexing_paused?).and_return(true)
|
||||
end
|
||||
|
||||
it 'puts the job to another queue without execution' do
|
||||
|
|
@ -55,7 +55,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::PauseControl::Server, :clean_gitlab_re
|
|||
|
||||
context 'when strategy is disabled' do
|
||||
before do
|
||||
stub_feature_flags(zoekt_pause_indexing: false)
|
||||
allow(Gitlab::CurrentSettings).to receive(:zoekt_indexing_paused?).and_return(false)
|
||||
end
|
||||
|
||||
it 'executes the job' do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe BulkImports::ExportStatus, :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
RSpec.describe BulkImports::ExportStatus, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
let_it_be(:relation) { 'labels' }
|
||||
let_it_be(:import) { create(:bulk_import) }
|
||||
let_it_be(:config) { create(:bulk_import_configuration, bulk_import: import) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Packages::Conan::Metadatum, type: :model do
|
||||
RSpec.describe Packages::Conan::Metadatum, type: :model, feature_category: :package_registry do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
describe 'relationships' do
|
||||
|
|
@ -70,16 +70,6 @@ RSpec.describe Packages::Conan::Metadatum, type: :model do
|
|||
it { is_expected.to eq(valid) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#conan_package_type' do
|
||||
it 'will not allow a package with a different package_type' do
|
||||
package = build('package')
|
||||
conan_metadatum = build('conan_metadatum', package: package)
|
||||
|
||||
expect(conan_metadatum).not_to be_valid
|
||||
expect(conan_metadatum.errors.to_a).to include('Package type must be Conan')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#recipe' do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Packages::Conan::Package, type: :model, feature_category: :package_registry do
|
||||
describe 'relationships' do
|
||||
it { is_expected.to have_one(:conan_metadatum).inverse_of(:package) }
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
subject { build_stubbed(:conan_package) }
|
||||
|
||||
describe '#name' do
|
||||
let(:fifty_one_characters) { 'f_b' * 17 }
|
||||
|
||||
it { is_expected.to allow_value('foo+bar').for(:name) }
|
||||
it { is_expected.to allow_value('foo_bar').for(:name) }
|
||||
it { is_expected.to allow_value('foo.bar').for(:name) }
|
||||
it { is_expected.to allow_value('9foo+bar').for(:name) }
|
||||
it { is_expected.not_to allow_value(fifty_one_characters).for(:name) }
|
||||
it { is_expected.not_to allow_value('+foobar').for(:name) }
|
||||
it { is_expected.not_to allow_value('.foobar').for(:name) }
|
||||
it { is_expected.not_to allow_value('%foo%bar').for(:name) }
|
||||
end
|
||||
|
||||
describe '#version' do
|
||||
let(:fifty_one_characters) { '1.2' * 17 }
|
||||
|
||||
it { is_expected.to allow_value('1.2').for(:version) }
|
||||
it { is_expected.to allow_value('1.2.3-beta').for(:version) }
|
||||
it { is_expected.to allow_value('1.2.3-pre1+build2').for(:version) }
|
||||
it { is_expected.not_to allow_value('1').for(:version) }
|
||||
it { is_expected.not_to allow_value(fifty_one_characters).for(:version) }
|
||||
it { is_expected.not_to allow_value('1./2.3').for(:version) }
|
||||
it { is_expected.not_to allow_value('.1.2.3').for(:version) }
|
||||
it { is_expected.not_to allow_value('+1.2.3').for(:version) }
|
||||
it { is_expected.not_to allow_value('%2e%2e%2f1.2.3').for(:version) }
|
||||
end
|
||||
|
||||
context 'for recipe uniqueness' do
|
||||
let_it_be(:package) { create(:conan_package) }
|
||||
let_it_be(:new_package) do
|
||||
build(:conan_package, project: package.project, name: package.name, version: package.version)
|
||||
end
|
||||
|
||||
it 'does not allow a conan package with same recipe' do
|
||||
expect(new_package).not_to be_valid
|
||||
expect(new_package.errors.to_a).to include('Package recipe already exists')
|
||||
end
|
||||
|
||||
it 'allows a conan package with same project, name, version and package_type but different channel' do
|
||||
new_package.conan_metadatum.package_channel = 'beta'
|
||||
expect(new_package).to be_valid
|
||||
end
|
||||
|
||||
it 'allows a conan package with same project, name, version and package_type, but different package username' do
|
||||
new_package.conan_metadatum.package_username = 'asdf99'
|
||||
expect(new_package).to be_valid
|
||||
end
|
||||
|
||||
context 'with pending destruction package' do
|
||||
let_it_be(:package) { create(:conan_package, :pending_destruction) }
|
||||
|
||||
it 'allows a conan package with same recipe' do
|
||||
expect(new_package).to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'scopes' do
|
||||
let_it_be(:package) { create(:conan_package) }
|
||||
|
||||
describe '.with_conan_channel' do
|
||||
subject { described_class.with_conan_channel('stable') }
|
||||
|
||||
it 'includes only packages with specified version' do
|
||||
is_expected.to include(package)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.with_conan_username' do
|
||||
subject do
|
||||
described_class.with_conan_username(
|
||||
Packages::Conan::Metadatum.package_username_from(full_path: package.project.full_path)
|
||||
)
|
||||
end
|
||||
|
||||
it 'includes only packages with specified version' do
|
||||
is_expected.to match_array([package])
|
||||
end
|
||||
end
|
||||
|
||||
describe '.preload_conan_metadatum' do
|
||||
subject(:packages) { described_class.preload_conan_metadatum }
|
||||
|
||||
it 'loads conan metadatum' do
|
||||
expect(packages.first.association(:conan_metadatum)).to be_loaded
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue