Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-05-16 15:19:50 +00:00
parent f6b1c1cf73
commit 5fb12406ad
111 changed files with 1102 additions and 565 deletions

View File

@ -1,5 +0,0 @@
---
# Cop supports --autocorrect.
RSpec/BeforeAll:
Exclude:
- 'ee/spec/support/shared_examples/finders/security/findings_finder_shared_examples.rb'

View File

@ -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 }) {

View File

@ -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;

View 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';

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,6 @@
query getManifestDetails($id: ContainerRepositoryID!, $reference: String!) {
containerRepository(id: $id) {
id
manifest(reference: $reference)
}
}

View File

@ -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();
}
};

View File

@ -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,

View File

@ -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) {

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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?

View File

@ -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

View File

@ -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)

View File

@ -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|

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,6 +1,7 @@
---
table_name: packages_packages
classes:
- Packages::Conan::Package
- Packages::Go::Package
- Packages::MlModel::Package
- Packages::Package

View File

@ -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

View File

@ -0,0 +1 @@
3b6c9657b2bd7ec2a772339716fa1c293c4352a709fdc71043d2265ade855d2a

View File

@ -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();

View File

@ -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. |

View File

@ -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. |

View File

@ -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]

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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:

View File

@ -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:

View File

@ -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**.

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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",

View File

@ -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'

View File

@ -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)

View File

@ -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

View File

@ -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' }

View File

@ -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

View File

@ -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

View File

@ -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',
});
});
});
});

View File

@ -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);
});
});
});
});

View File

@ -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', () => {

View File

@ -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}" }

View File

@ -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

View File

@ -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) }

View File

@ -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: {

View File

@ -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 }))

View File

@ -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

View File

@ -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)

View File

@ -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) }

View File

@ -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: {

View File

@ -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(

View File

@ -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

View File

@ -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 }

View File

@ -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)

View File

@ -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

View File

@ -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 }

View File

@ -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

View File

@ -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 } } } }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) }

View File

@ -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) }

View File

@ -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) }

View File

@ -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) }

View File

@ -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) }

View File

@ -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) }

View File

@ -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 }

View File

@ -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) }

View File

@ -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') }

View File

@ -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

View File

@ -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') }

View File

@ -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) }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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([])

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) }

View File

@ -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

View File

@ -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