Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-01-29 12:06:57 +00:00
parent 1c3cf2e3cd
commit a73ecda21e
48 changed files with 548 additions and 260 deletions

View File

@ -53,6 +53,18 @@ rails-production-server-boot-puma-cng:
- retry_times_sleep 10 5 "curl http://127.0.0.1:8080"
- kill $(jobs -p)
ruby_syntax:
extends:
- .preflight-job-base
before_script:
- source scripts/utils.sh
image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}
parallel:
matrix:
- RUBY_VERSION: ["3.0", "3.1", "3.2"]
script:
- run_timed_command "fail_on_warnings scripts/lint/check_ruby_syntax.rb"
no-ee-check:
extends:
- .preflight-job-base

View File

@ -2939,6 +2939,11 @@
- <<: *if-default-refs
changes: *code-patterns
.preflight:rules:ruby_syntax:
rules:
- <<: *if-default-refs
changes: *backend-patterns
.preflight:rules:no-ee-check:
rules:
- <<: *if-not-foss

View File

@ -4370,7 +4370,6 @@ RSpec/FeatureCategory:
- 'spec/models/concerns/signature_type_spec.rb'
- 'spec/models/concerns/sortable_spec.rb'
- 'spec/models/concerns/spammable_spec.rb'
- 'spec/models/concerns/stepable_spec.rb'
- 'spec/models/concerns/strip_attribute_spec.rb'
- 'spec/models/concerns/subquery_spec.rb'
- 'spec/models/concerns/subscribable_spec.rb'

View File

@ -2654,7 +2654,6 @@ RSpec/NamedSubject:
- 'spec/models/concerns/resolvable_note_spec.rb'
- 'spec/models/concerns/runners_token_prefixable_spec.rb'
- 'spec/models/concerns/spammable_spec.rb'
- 'spec/models/concerns/stepable_spec.rb'
- 'spec/models/concerns/subquery_spec.rb'
- 'spec/models/concerns/token_authenticatable_spec.rb'
- 'spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb'

View File

@ -2,8 +2,16 @@
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import { makeLoadVersionsErrorMessage } from '~/ml/model_registry/translations';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { s__ } from '~/locale';
import getModelVersionsQuery from '../graphql/queries/get_model_versions.query.graphql';
import { GRAPHQL_PAGE_SIZE, MODEL_ENTITIES } from '../constants';
import {
GRAPHQL_PAGE_SIZE,
LIST_KEY_CREATED_AT,
LIST_KEY_VERSION,
MODEL_ENTITIES,
SORT_KEY_CREATED_AT,
SORT_KEY_ORDER,
} from '../constants';
import SearchableList from './searchable_list.vue';
import EmptyState from './empty_state.vue';
import ModelVersionRow from './model_version_row.vue';
@ -24,6 +32,8 @@ export default {
return {
modelVersions: {},
errorMessage: undefined,
skipQueries: true,
queryVariables: {},
};
},
apollo: {
@ -38,6 +48,9 @@ export default {
error(error) {
this.handleError(error);
},
skip() {
return this.skipQueries;
},
},
},
computed: {
@ -50,31 +63,25 @@ export default {
pageInfo() {
return this.modelVersions?.pageInfo ?? {};
},
queryVariables() {
return {
id: this.gid,
first: GRAPHQL_PAGE_SIZE,
};
},
versions() {
return this.modelVersions?.nodes ?? [];
},
},
methods: {
fetchPage(pageInfo) {
const variables = {
...this.queryVariables,
...pageInfo,
fetchPage(variables) {
this.queryVariables = {
id: this.gid,
first: GRAPHQL_PAGE_SIZE,
...variables,
version: variables.name,
orderBy: variables.orderBy?.toUpperCase() || SORT_KEY_CREATED_AT,
sort: variables.sort?.toUpperCase() || SORT_KEY_ORDER,
};
this.$apollo.queries.modelVersions
.fetchMore({
variables,
updateQuery: (previousResult, { fetchMoreResult }) => {
return fetchMoreResult;
},
})
.catch(this.handleError);
this.errorMessage = null;
this.skipQueries = false;
this.$apollo.queries.modelVersions.fetchMore({});
},
handleError(error) {
this.errorMessage = makeLoadVersionsErrorMessage(error.message);
@ -82,13 +89,26 @@ export default {
},
},
modelVersionEntity: MODEL_ENTITIES.modelVersion,
sortableFields: [
{
orderBy: LIST_KEY_VERSION,
label: s__('MlExperimentTracking|Version'),
},
{
orderBy: LIST_KEY_CREATED_AT,
label: s__('MlExperimentTracking|Created at'),
},
],
};
</script>
<template>
<searchable-list
show-search
:page-info="pageInfo"
:items="versions"
:error-message="errorMessage"
:is-loading="isLoading"
:sortable-fields="$options.sortableFields"
@fetch-page="fetchPage"
>
<template #empty-state>

View File

@ -1,6 +1,10 @@
import { s__ } from '~/locale';
export const LIST_KEY_CREATED_AT = 'created_at';
export const LIST_KEY_VERSION = 'version';
export const SORT_KEY_CREATED_AT = 'CREATED_AT';
export const SORT_KEY_ORDER = 'DESC';
export const BASE_SORT_FIELDS = Object.freeze([
{
orderBy: 'name',

View File

@ -1,7 +1,24 @@
query getModelVersions($id: MlModelID!, $first: Int, $last: Int, $after: String, $before: String) {
query getModelVersions(
$id: MlModelID!
$version: String
$orderBy: MlModelVersionsOrderBy
$sort: SortDirectionEnum
$first: Int
$last: Int
$after: String
$before: String
) {
mlModel(id: $id) {
id
versions(after: $after, before: $before, first: $first, last: $last) {
versions(
version: $version
orderBy: $orderBy
sort: $sort
after: $after
before: $before
first: $first
last: $last
) {
count
nodes {
id

View File

@ -1,35 +0,0 @@
# frozen_string_literal: true
module Stepable
extend ActiveSupport::Concern
def steps
self.class._all_steps
end
def execute_steps
initial_result = {}
steps.inject(initial_result) do |previous_result, callback|
result = method(callback).call(previous_result)
if result[:status] != :success
result[:last_step] = callback
break result
end
result
end
end
class_methods do
def _all_steps
@_all_steps ||= []
end
def steps(*methods)
_all_steps.concat methods
end
end
end

View File

@ -33,6 +33,7 @@ module Organizations
delegate :description, :description_html, :avatar, :avatar_url, :remove_avatar!, to: :organization_detail
accepts_nested_attributes_for :organization_detail
accepts_nested_attributes_for :organization_users
def self.default_organization
find_by(id: DEFAULT_ORGANIZATION_ID)

View File

@ -26,10 +26,17 @@ module Packages
scope :stale, -> { where(package_id: nil) }
scope :pending_destruction, -> { stale.default }
scope :with_file_name, ->(file_name) { where(file: file_name) }
scope :with_signature, ->(signature) { where(signature: signature) }
scope :with_file_name, ->(file_name) { where(arel_table[:file].lower.eq(file_name.downcase)) }
scope :with_signature, ->(signature) { where(arel_table[:signature].lower.eq(signature.downcase)) }
scope :with_file_sha256, ->(checksums) { where(file_sha256: checksums) }
def self.find_by_signature_and_file_and_checksum(signature, file_name, checksums)
with_signature(signature)
.with_file_name(file_name)
.with_file_sha256(checksums)
.take
end
private
def set_object_storage_key

View File

@ -16,11 +16,11 @@ module WorkItems
end
def self.quick_action_commands
[:set_parent, :add_child]
[:set_parent, :add_child, :remove_parent]
end
def self.quick_action_params
[:set_parent, :add_child]
[:set_parent, :add_child, :remove_parent]
end
def self.sync_params
@ -30,9 +30,11 @@ module WorkItems
def self.process_quick_action_param(param_name, value)
return super unless param_name.in?(quick_action_params) && value.present?
return { parent: value } if param_name == :set_parent
return { children: value } if param_name == :add_child
if [:set_parent, :remove_parent].include?(param_name)
{ parent: value.is_a?(WorkItem) ? value : nil }
else
{ children: value }
end
end
def self.process_sync_params(params)

View File

@ -3,13 +3,17 @@
module Organizations
class CreateService < ::Organizations::BaseService
def execute
return error_no_permissions unless current_user&.can?(:create_organization)
return error_no_permissions unless can?(current_user, :create_organization)
organization = Organization.create(params)
add_organization_owner_attributes
organization = Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification
.allow_cross_database_modification_within_transaction(
url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/438757'
) do
Organization.create(params)
end
if organization.persisted?
add_organization_owner(organization)
ServiceResponse.success(payload: { organization: organization })
else
error_creating(organization)
@ -18,8 +22,8 @@ module Organizations
private
def add_organization_owner(organization)
organization.organization_users.create(user: current_user, access_level: :owner)
def add_organization_owner_attributes
@params[:organization_users_attributes] = [{ user: current_user, access_level: :owner }]
end
def error_no_permissions

View File

@ -1,8 +0,0 @@
---
name: use_primary_and_secondary_stores_for_shared_state
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134483
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/429884
milestone: '16.6'
type: development
group: group::scalability
default_enabled: false

View File

@ -1,8 +0,0 @@
---
name: use_primary_store_as_default_for_shared_state
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134483
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/429884
milestone: '16.6'
type: development
group: group::scalability
default_enabled: false

View File

@ -41,5 +41,5 @@ end
# 2. Rails.cache
# 3. HTTP clients
Gitlab::Redis::ALL_CLASSES.each do |redis_instance|
redis_instance.with { nil } unless redis_instance == Gitlab::Redis::ClusterSharedState
redis_instance.with { nil }
end

View File

@ -0,0 +1,26 @@
---
key_path: redis_hll_counters.quickactions.i_quickactions_remove_parent_monthly
name: quickactions_remove_parent_monthly
description: Count of MAU using the `/remove_parent` quick action
product_section: dev
product_stage: plan
product_group: product_planning
value_type: number
status: active
milestone: "16.9"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142174
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
options:
events:
- i_quickactions_remove_parent
performance_indicator_type: []
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -0,0 +1,26 @@
---
key_path: redis_hll_counters.quickactions.i_quickactions_remove_parent_weekly
name: quickactions_remove_parent_weekly
description: Count of WAU using the `/remove_parent` quick action
product_section: dev
product_stage: plan
product_group: product_planning
value_type: number
status: active
milestone: "16.9"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142174
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
options:
events:
- i_quickactions_remove_parent
performance_indicator_type: []
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddIndexPackagesNugetSymbolsOnLowercaseSignatureAndFileName < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '16.9'
INDEX_NAME = 'idx_pkgs_nuget_symbols_on_lowercase_signature_and_file_name'
def up
add_concurrent_index :packages_nuget_symbols, 'lower(signature), lower(file)', name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :packages_nuget_symbols, INDEX_NAME
end
end

View File

@ -0,0 +1 @@
ef72ce15563a5841276fcbf79c02a3e657511f12b55cecf277d0c4287d15c363

View File

@ -32427,6 +32427,8 @@ CREATE INDEX idx_pkgs_installable_package_files_on_package_id_id_file_name ON pa
CREATE INDEX idx_pkgs_npm_metadata_caches_on_id_and_project_id_and_status ON packages_npm_metadata_caches USING btree (id) WHERE ((project_id IS NULL) AND (status = 0));
CREATE INDEX idx_pkgs_nuget_symbols_on_lowercase_signature_and_file_name ON packages_nuget_symbols USING btree (lower(signature), lower(file));
CREATE INDEX idx_pkgs_on_project_id_name_version_on_installable_terraform ON packages_packages USING btree (project_id, name, version, id) WHERE ((package_type = 12) AND (status = ANY (ARRAY[0, 1])));
CREATE INDEX idx_proj_feat_usg_on_jira_dvcs_cloud_last_sync_at_and_proj_id ON project_feature_usages USING btree (jira_dvcs_cloud_last_sync_at, project_id) WHERE (jira_dvcs_cloud_last_sync_at IS NOT NULL);

View File

@ -757,11 +757,11 @@ See our [Redis guidelines](redis.md) for more information about how GitLab uses
#### Registry
- [Project page](https://github.com/docker/distribution/blob/master/README.md)
- [Project page](https://gitlab.com/gitlab-org/container-registry)
- Configuration:
- [Omnibus](../update/upgrading_from_source.md#10-install-libraries-migrations-etc)
- [Omnibus](../administration/packages/container_registry.md)
- [Charts](https://docs.gitlab.com/charts/charts/registry/)
- [Source](../administration/packages/container_registry.md#enable-the-container-registry)
- [Source](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/configuration.md?ref_type=heads)
- [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/main/doc/howto/registry.md)
- Layer: Core Service (Processor)
- GitLab.com: [GitLab container registry](../user/packages/container_registry/build_and_push_images.md#use-gitlab-cicd)

View File

@ -7,8 +7,21 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Support for Experiment, Beta, and Generally Available features
There are cases where GitLab would like to validate the edge-cases of scale, support, and maintenance burden of features in their current form for every designed use case.
There are also scenarios where a feature is not complete enough to be considered an [MVC](https://handbook.gitlab.com/handbook/product/product-principles/#the-minimal-viable-change-mvc).
In these cases, GitLab has the option to release features as Experiment, Beta, or Limited Availability, and users can opt-in and test the new experience.
Features might not be fully documented or supported in the Experiment or Beta phases.
Please note that some features may not be aligned to these recommendations if they were developed before the recommendations were in place or if the group determined an alternative implementation approach was needed.
Product development teams should refrain from making changes that they reasonably believe could create significant risks or friction for GitLab users or the platform, such as:
- Risking damage or exfiltration of existing production data accessed by our users.
- Destabilizing other parts of the application.
- Introducing friction into high monthly active user (MAU) areas.
Some GitLab features are released as Experiment or Beta versions and are
[not fully supported](https://about.gitlab.com/support/statement-of-support/#alpha-beta-features).
[not fully supported](https://about.gitlab.com/support/statement-of-support/#experiment-beta-features).
All other features are considered to be Generally Available (GA).
## Experiment
@ -42,6 +55,7 @@ Beta features are:
- May not be ready for production use.
- Support on a commercially-reasonable effort basis.
- Not required or necessary for most features.
- May be unstable.
- Configuration and dependencies unlikely to change.
- Features and functions unlikely to change. However, breaking changes may occur outside of major releases or with less notice than for Generally Available features.
@ -75,5 +89,23 @@ The experimental features are only shown when people/organizations opt-in to exp
## All features are in production
All features that are available on GitLab.com are considered "in production."
All features that are available on GitLab.com are considered "in production".
Because all Experiment, Beta, and Generally Available features are available on GitLab.com, they are all considered to be in production.
## Experiment, Beta and Limited Availability Exit Criteria
To ensure the phases before General Availability are as short as possible each phase of Experiment, Beta and LA should include exit criteria.
This encourages rapid iteration and reduces [cycle time](https://handbook.gitlab.com/handbook/values/#reduce-cycle-time).
GitLab Product Managers will take the following into account when deciding what exit criteria to apply to their Experimental, Beta, and Limited Availability features:
- **Time**: Define an end date at which point the feature will be General Availability.
- Consider setting a time-bound target metric that will define readiness for exit into GA (e.g. X number of customers retained MoM over 6 months after launch of Experiment, X% growth of free and paid users in three months since launch Beta, etc.)
- Be mindful of balancing time to market, user experience, and richness of experience. Some Beta programs have lasted 1 milestone while other have lasted a couple of years.
- **Feedback**: Define the minimum number of customers that have been onboarded and interviewed.
- Consider also setting a time bound when using user feedback as an exit criteria for leaving a phases. If a given time period elapses and we can not solicit feedback from enough users, it is better to ship what we have and iterate on it as a GA at that point rather than maintain a pre-GA state.
- **Limited Feature Completion**: Determine if there is functionality that should be completed before moving to General Availability.
- Be wary of including "just one more" feature. Iteration will be easier and more effective with more feedback from more users so getting to General Availability is preferred.
- **System Performance metrics**: Determine the criteria that the platform has shown before being ready for General Availability. Examples include response times and successfully handling a number of requests per second.
- **Success criteria**: Not all features may reach GA. It is OK to pivot if early feedback indicates that a different direction would provide more value or a better user experience. If open questions must be answered to decide if the feature is worth putting in the product, list and answer those.
For the exit criteria of **AI features**, in addition to the above, see the [UX maturity requirements](https://handbook.gitlab.com/handbook/product/ai/ux-maturity/).

View File

@ -47,7 +47,7 @@ The following Rake tasks are available for use with GitLab:
| [Uploads sanitize](../administration/raketasks/uploads/sanitize.md) | Remove EXIF data from images uploaded to earlier versions of GitLab. |
| [Service Data](../development/internal_analytics/service_ping/troubleshooting.md#generate-service-ping) | Generate and troubleshoot [Service Ping](../development/internal_analytics/service_ping/index.md). |
| [User management](user_management.md) | Perform user management tasks. |
| [Webhooks administration](web_hooks.md) | Maintain project webhooks. |
| [Webhook administration](web_hooks.md) | Maintain project webhooks. |
| [X.509 signatures](x509_signatures.md) | Update X.509 commit signatures, which can be useful if the certificate store changed. |
To list all available Rake tasks:

View File

@ -4,7 +4,7 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Webhooks administration Rake tasks
# Webhook administration Rake tasks
DETAILS:
**Tier:** Free, Premium, Ultimate

View File

@ -363,6 +363,7 @@ after the limits change in January, 2021:
| **GitLab Pages** TLS connections (for a given **GitLab Pages domain**) | | **400** requests per **10 seconds** |
| **Pipeline creation** requests (for a given **project, user, and commit**) | | **25** requests per minute |
| **Alert integration endpoint** requests (for a given **project**) | | **3600** requests per hour |
| **[Pull mirroring](../project/repository/mirror/pull.md)** intervals | **5** minutes | **5** minutes |
More details are available on the rate limits for
[protected paths](#protected-paths-throttle) and

View File

@ -329,6 +329,12 @@ For a safer development environment, you can use the [GitLab Development Kit (GD
You can [review recently triggered webhook payloads](#troubleshooting) in GitLab settings. For each webhook event, a detail page exists with information about the data GitLab sends and receives from the webhook endpoint.
## Related topics
- [Project hooks API](../../../api/projects.md#hooks)
- [Group hooks API](../../../api/groups.md#hooks)
- [System hooks API](../../../api/system_hooks.md)
## Troubleshooting
> - **Recent events** for group webhooks [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325642) in GitLab 15.3.

View File

@ -167,6 +167,7 @@ To auto-format this table, use the VS Code Markdown Table formatter: `https://do
| `/reassign @user1 @user2` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Replace current assignees with those specified. |
| `/relabel ~label1 ~label2` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Replace current labels with those specified. |
| `/remove_due_date` | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes | Remove due date. |
| `/remove_parent` | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes | Removes the parent work item. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/434344) in GitLab 16.9. |
| `/reopen` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Reopen. |
| `/set_parent <work_item>` | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes | Set parent work item to `<work_item>`. The `<work_item>` value should be in the format of `#iid`, `group/project#iid`, or a URL to a work item. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/420798) in GitLab 16.5. |
| `/shrug <comment>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Append the comment with `¯\_(ツ)_/¯`. |

View File

@ -301,7 +301,7 @@ In GitLab 13.10, if a project has the **Reject unsigned commits** push rule, the
create commits through the GitLab Web IDE.
To allow committing through the Web IDE on a project with this push rule, a GitLab administrator
must disable the feature flag `reject_unsigned_commits_by_gitlab`. [with a flag](../../../administration/feature_flags.md)
must disable the feature flag `reject_unsigned_commits_by_gitlab` [with a flag](../../../administration/feature_flags.md).
```ruby
Feature.disable(:reject_unsigned_commits_by_gitlab)

View File

@ -79,16 +79,14 @@ module API
project_or_group_without_auth
# upcase the age part of the signature in case we received it in lowercase:
# https://github.com/dotnet/symstore/blob/main/docs/specs/SSQP_Key_Conventions.md#key-formatting-basic-rules
signature = declared_params[:signature].sub(/.{8}\z/, &:upcase)
checksums = headers['Symbolchecksum'].scan(SHA256_REGEX).flatten
symbol = ::Packages::Nuget::Symbol
.with_signature(signature)
.with_file_name(declared_params[:file_name])
.with_file_sha256(checksums)
.first
.find_by_signature_and_file_and_checksum(
declared_params[:signature],
declared_params[:file_name],
checksums
)
not_found!('Symbol') unless symbol

View File

@ -309,7 +309,7 @@ module Gitlab
cache_identity = Gitlab::Redis::Cache.with(&:inspect) # rubocop:disable CodeReuse/ActiveRecord -- This is not AR
Gitlab::Redis::SharedState.with do |redis|
yield redis unless cache_identity == redis.default_store.inspect
yield redis unless cache_identity == redis.inspect
end
block_result

View File

@ -40,6 +40,20 @@ module Gitlab
@execution_message[:set_parent] = success_msg[:set_parent]
end
desc { _('Remove work item parent') }
explanation do
format(
_("Remove %{parent_ref} as this work item's parent."),
parent_ref: work_item_parent.to_reference(quick_action_target)
)
end
types WorkItem
condition { work_item_parent.present? && can_admin_link? }
command :remove_parent do
@updates[:remove_parent] = true
@execution_message[:remove_parent] = success_msg[:remove_parent]
end
desc { _('Add children to work item') }
explanation do |child_param|
format(_("Add %{child_ref} to this work item as child(ren)."), child_ref: child_param)
@ -126,10 +140,15 @@ module Gitlab
type: _('Type changed successfully.'),
promote_to: _("Work item promoted successfully."),
set_parent: _('Work item parent set successfully'),
remove_parent: _('Work item parent removed successfully'),
add_child: _('Child work item(s) added successfully')
}
end
def work_item_parent
quick_action_target.work_item_parent
end
def supports_parent?
::WorkItems::HierarchyRestriction.find_by_child_type_id(quick_action_target.work_item_type_id).present?
end

View File

@ -10,7 +10,6 @@ module Gitlab
ALL_CLASSES = [
Gitlab::Redis::BufferedCounter,
Gitlab::Redis::Cache,
Gitlab::Redis::ClusterSharedState,
Gitlab::Redis::DbLoadBalancing,
Gitlab::Redis::FeatureFlag,
Gitlab::Redis::Queues,

View File

@ -1,13 +0,0 @@
# frozen_string_literal: true
module Gitlab
module Redis
class ClusterSharedState < ::Gitlab::Redis::Wrapper
class << self
def config_fallback
SharedState
end
end
end
end
end

View File

@ -2,10 +2,7 @@
module Gitlab
module Redis
class SharedState < ::Gitlab::Redis::MultiStoreWrapper
def self.multistore
MultiStore.new(ClusterSharedState.pool, pool, store_name)
end
class SharedState < ::Gitlab::Redis::Wrapper
end
end
end

View File

@ -5806,9 +5806,6 @@ msgstr ""
msgid "Analytics|Updating visualization %{visualizationName}"
msgstr ""
msgid "Analytics|Usage overview for %{namespaceName} group"
msgstr ""
msgid "Analytics|Use the visualization designer to create custom visualizations. After you save a visualization, you can add it to a dashboard."
msgstr ""
@ -31394,6 +31391,9 @@ msgstr ""
msgid "MlExperimentTracking|No name"
msgstr ""
msgid "MlExperimentTracking|Version"
msgstr ""
msgid "MlModelRegistry|%d model"
msgid_plural "MlModelRegistry|%d models"
msgstr[0] ""
@ -40787,6 +40787,9 @@ msgstr ""
msgid "Remove %{displayReference}"
msgstr ""
msgid "Remove %{parent_ref} as this work item's parent."
msgstr ""
msgid "Remove %{ruleName}"
msgstr ""
@ -40952,6 +40955,9 @@ msgstr ""
msgid "Remove weight"
msgstr ""
msgid "Remove work item parent"
msgstr ""
msgid "Removed"
msgstr ""
@ -45098,7 +45104,7 @@ msgstr ""
msgid "SecurityReports|Report has expired"
msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgid "SecurityReports|Results show vulnerability findings from the latest successful %{helpPageLinkStart}pipeline%{helpPageLinkEnd}."
msgstr ""
msgid "SecurityReports|Scan details"
@ -55758,6 +55764,9 @@ msgstr ""
msgid "Work in progress limit"
msgstr ""
msgid "Work item parent removed successfully"
msgstr ""
msgid "Work item parent set successfully"
msgstr ""
@ -58158,6 +58167,9 @@ msgid_plural "ciReport|Used by %{packagesString}, and %{lastPackage}"
msgstr[0] ""
msgstr[1] ""
msgid "ciReport|View all pipeline findings"
msgstr ""
msgid "ciReport|View full report"
msgstr ""

View File

@ -0,0 +1,25 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require_relative "../../tooling/lib/tooling/check_ruby_syntax"
files = `git ls-files -z`.split("\0")
checker = Tooling::CheckRubySyntax.new(files)
puts format("Checking %{files} Ruby files...", files: checker.ruby_files.size)
errors = checker.run
puts
if errors.any?
puts "Syntax errors found (#{errors.size}):"
puts errors
exit 1
else
puts "No syntax errors found."
exit 0
end

View File

@ -9,12 +9,11 @@ import SearchableList from '~/ml/model_registry/components/searchable_list.vue';
import ModelVersionRow from '~/ml/model_registry/components/model_version_row.vue';
import getModelVersionsQuery from '~/ml/model_registry/graphql/queries/get_model_versions.query.graphql';
import EmptyState from '~/ml/model_registry/components/empty_state.vue';
import { GRAPHQL_PAGE_SIZE, MODEL_ENTITIES } from '~/ml/model_registry/constants';
import { MODEL_ENTITIES } from '~/ml/model_registry/constants';
import {
emptyModelVersionsQuery,
modelVersionsQuery,
graphqlModelVersions,
graphqlPageInfo,
} from '../graphql_mock_data';
Vue.use(VueApollo);
@ -79,11 +78,19 @@ describe('ModelVersionList', () => {
});
describe('when list is loaded with data', () => {
let resolver;
beforeEach(async () => {
mountComponent();
resolver = jest.fn().mockResolvedValue(modelVersionsQuery());
mountComponent({ resolver });
await waitForPromises();
});
it('calls query only once on setup', () => {
expect(resolver).toHaveBeenCalledTimes(1);
});
it('Passes items to list', () => {
expect(findSearchableList().props('items')).toEqual(graphqlModelVersions);
});
@ -115,13 +122,22 @@ describe('ModelVersionList', () => {
findSearchableList().vm.$emit('fetch-page', {
after: 'eyJpZCI6IjIifQ',
first: 30,
id: 'gid://gitlab/Ml::Model/2',
name: '1.0.0',
orderBy: 'version',
sort: 'asc',
});
await waitForPromises();
expect(resolver).toHaveBeenLastCalledWith(
expect.objectContaining({ after: graphqlPageInfo.endCursor, first: GRAPHQL_PAGE_SIZE }),
expect.objectContaining({
id: 'gid://gitlab/Ml::Model/2',
after: 'eyJpZCI6IjIifQ',
first: 30,
version: '1.0.0',
orderBy: 'VERSION',
sort: 'ASC',
}),
);
});
});

View File

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Redis::ClusterSharedState, feature_category: :redis do
include_examples "redis_new_instance_shared_examples", 'cluster_shared_state', Gitlab::Redis::SharedState
end

View File

@ -6,5 +6,4 @@ RSpec.describe Gitlab::Redis::SharedState do
let(:instance_specific_config_file) { "config/redis.shared_state.yml" }
include_examples "redis_shared_examples"
include_examples "multi_store_wrapper_shared_examples"
end

View File

@ -1,115 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Stepable do
let(:described_class) do
Class.new do
include Stepable
attr_writer :return_non_success
steps :method1, :method2, :method3
def execute
execute_steps
end
private
def method1(_result)
{ status: :success }
end
def method2(result)
return { status: :not_a_success } if @return_non_success
result.merge({ status: :success, variable1: 'var1', excluded_variable: 'a' })
end
def method3(result)
result.except(:excluded_variable).merge({ status: :success, variable2: 'var2' })
end
end
end
let(:prepended_module) do
Module.new do
extend ActiveSupport::Concern
prepended do
steps :appended_method1
end
private
def appended_method1(previous_result)
previous_result.merge({ status: :success })
end
end
end
before do
described_class.prepend(prepended_module)
end
it 'stops after the first non success status' do
subject.return_non_success = true
expect(subject).not_to receive(:method3)
expect(subject).not_to receive(:appended_method1)
expect(subject.execute).to eq(
status: :not_a_success,
last_step: :method2
)
end
context 'when all methods return success' do
it 'calls all methods in order' do
expect(subject).to receive(:method1).and_call_original.ordered
expect(subject).to receive(:method2).and_call_original.ordered
expect(subject).to receive(:method3).and_call_original.ordered
expect(subject).to receive(:appended_method1).and_call_original.ordered
subject.execute
end
it 'merges variables returned by all steps' do
expect(subject.execute).to eq(
status: :success,
variable1: 'var1',
variable2: 'var2'
)
end
it 'can modify results of previous steps' do
expect(subject.execute).not_to include(excluded_variable: 'a')
end
end
context 'with multiple stepable classes' do
let(:other_class) do
Class.new do
include Stepable
steps :other_method1, :other_method2
private
def other_method1
{ status: :success }
end
def other_method2
{ status: :success }
end
end
end
it 'does not leak steps' do
expect(other_class.new.steps).to contain_exactly(:other_method1, :other_method2)
expect(subject.steps).to contain_exactly(:method1, :method2, :method3, :appended_method1)
end
end
end

View File

@ -67,6 +67,7 @@ RSpec.describe Organizations::Organization, type: :model, feature_category: :cel
describe 'nested attributes' do
it { is_expected.to accept_nested_attributes_for(:organization_detail) }
it { is_expected.to accept_nested_attributes_for(:organization_users) }
end
context 'when using scopes' do

View File

@ -52,8 +52,16 @@ RSpec.describe Packages::Nuget::Symbol, type: :model, feature_category: :package
let_it_be(:signature) { 'signature' }
let_it_be(:symbol) { create(:nuget_symbol, signature: signature) }
it 'returns symbols with the given signature' do
expect(with_signature).to eq([symbol])
shared_examples 'returns symbols with the given signature' do
it { is_expected.to contain_exactly(symbol) }
end
it_behaves_like 'returns symbols with the given signature'
context 'when signature is in uppercase' do
subject(:with_signature) { described_class.with_signature(signature.upcase) }
it_behaves_like 'returns symbols with the given signature'
end
end
@ -63,12 +71,22 @@ RSpec.describe Packages::Nuget::Symbol, type: :model, feature_category: :package
let_it_be(:file_name) { 'file_name' }
let_it_be(:symbol) { create(:nuget_symbol) }
shared_examples 'returns symbols with the given file_name' do
it 'returns symbols with the given file_name' do
expect(with_file_name).to contain_exactly(symbol)
end
end
before do
symbol.update_column(:file, file_name)
end
it 'returns symbols with the given file_name' do
expect(with_file_name).to eq([symbol])
it_behaves_like 'returns symbols with the given file_name'
context 'when file_name is in uppercase' do
subject(:with_file_name) { described_class.with_file_name(file_name.upcase) }
it_behaves_like 'returns symbols with the given file_name'
end
end
@ -82,6 +100,22 @@ RSpec.describe Packages::Nuget::Symbol, type: :model, feature_category: :package
expect(with_file_sha256).to eq([symbol])
end
end
describe '.find_by_signature_and_file_and_checksum' do
subject { described_class.find_by_signature_and_file_and_checksum(signature, file_name, checksum) }
let_it_be(:signature) { 'signature' }
let_it_be(:file_name) { 'file.pdb' }
let_it_be(:checksum) { OpenSSL::Digest.hexdigest('SHA256', 'checksums') }
let_it_be(:symbol) { create(:nuget_symbol, signature: signature, file_sha256: checksum) }
let_it_be(:another_symbol) { create(:nuget_symbol) }
before do
symbol.update_column(:file, file_name)
end
it { is_expected.to eq(symbol) }
end
end
describe 'callbacks' do

View File

@ -426,6 +426,28 @@ RSpec.describe Notes::QuickActionsService, feature_category: :team_planning do
end
end
describe '/remove_parent' do
let_it_be_with_reload(:parent) { create(:work_item, :objective, project: project) }
let_it_be_with_reload(:noteable) { create(:work_item, :objective, project: project) }
let_it_be(:note_text) { "/remove_parent" }
let_it_be(:note) { create(:note, noteable: noteable, project: project, note: note_text) }
before do
create(:parent_link, work_item_parent: parent, work_item: noteable)
end
it 'leaves the note empty' do
expect(execute(note)).to be_empty
end
it 'removes work item parent' do
execute(note)
expect(noteable.valid?).to be_truthy
expect(noteable.work_item_parent).to eq(nil)
end
end
describe '/promote_to' do
shared_examples 'promotes work item' do |from:, to:|
it 'leaves the note empty' do

View File

@ -2770,6 +2770,42 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
expect(updates).to eq(set_parent: parent)
end
end
context '/remove_parent command' do
let_it_be_with_reload(:work_item) { create(:work_item, :task, project: project) }
let(:content) { "/remove_parent" }
context 'when a parent is not present' do
it 'is empty' do
_, explanations = service.explain(content, work_item)
expect(explanations).to eq([])
end
end
context 'when a parent is present' do
let_it_be(:parent) { create(:work_item, :issue, project: project) }
before do
create(:parent_link, work_item_parent: parent, work_item: work_item)
end
it 'returns correct explanation' do
_, explanations = service.explain(content, work_item)
expect(explanations)
.to contain_exactly("Remove #{parent.to_reference(work_item)} as this work item's parent.")
end
it 'returns success message' do
_, updates, message = service.execute(content, work_item)
expect(updates).to eq(remove_parent: true)
expect(message).to eq('Work item parent removed successfully')
end
end
end
end
describe '#explain' do

View File

@ -7152,7 +7152,6 @@
- './spec/models/concerns/sha_attribute_spec.rb'
- './spec/models/concerns/sortable_spec.rb'
- './spec/models/concerns/spammable_spec.rb'
- './spec/models/concerns/stepable_spec.rb'
- './spec/models/concerns/strip_attribute_spec.rb'
- './spec/models/concerns/subscribable_spec.rb'
- './spec/models/concerns/taggable_queries_spec.rb'

View File

@ -761,7 +761,7 @@ RSpec.shared_examples 'nuget symbol file endpoint' do
end
end
context 'with valid target' do
shared_examples 'successful response' do
it 'returns the symbol file' do
subject
@ -771,6 +771,10 @@ RSpec.shared_examples 'nuget symbol file endpoint' do
end
end
context 'with valid target' do
it_behaves_like 'successful response'
end
context 'when target does not exist' do
let(:target) { double(id: 1234567890) }
@ -797,6 +801,13 @@ RSpec.shared_examples 'nuget symbol file endpoint' do
it_behaves_like 'returning response status', :bad_request
end
end
context 'when signature & filename are in uppercase' do
let(:filename) { symbol.file.filename.upcase }
let(:signature) { symbol.signature.upcase }
it_behaves_like 'successful response'
end
end
context 'with nuget_symbol_server_enabled setting disabled' do

View File

@ -0,0 +1,84 @@
# frozen_string_literal: true
require "fast_spec_helper"
require "fileutils"
require "rspec-parameterized"
require_relative "../../../../tooling/lib/tooling/check_ruby_syntax"
RSpec.describe Tooling::CheckRubySyntax, feature_category: :tooling do
let(:files) { Dir.glob("**/*") }
subject(:checker) { described_class.new(files) }
around do |example|
Dir.mktmpdir do |dir|
Dir.chdir(dir) do
example.run
end
end
end
describe "#ruby_files" do
subject { checker.ruby_files }
context "without files" do
it { is_expected.to eq([]) }
end
context "with files ending with .rb" do
before do
FileUtils.touch("foo.rb")
FileUtils.touch("bar.rb")
FileUtils.touch("baz.erb")
end
it { is_expected.to contain_exactly("foo.rb", "bar.rb") }
end
context "with special Ruby files" do
let(:files) do
%w[foo/Guardfile danger/Dangerfile gems/Gemfile Rakefile]
end
before do
files.each do |file|
FileUtils.mkdir_p(File.dirname(file))
FileUtils.touch(file)
end
end
it { is_expected.to match_array(files) }
end
end
describe "#run" do
subject(:errors) { checker.run }
shared_examples "no errors" do
it { is_expected.to be_empty }
end
context "without files" do
include_examples "no errors"
end
context "with perfect Ruby code" do
before do
File.write("perfect.rb", "perfect = code")
end
include_examples "no errors"
end
context "with invalid Ruby code" do
before do
File.write("invalid.rb", "invalid,")
end
it "has errors" do
expect(errors).to include(a_kind_of(SyntaxError))
end
end
end
end

View File

@ -0,0 +1,41 @@
# frozen_string_literal: true
require 'set' # rubocop:disable Lint/RedundantRequireStatement -- Ruby 3.1 and earlier needs this. Drop this line after Ruby 3.2+ is only supported.
module Tooling
# Checks passed files for valid Ruby syntax.
#
# It does not check for compile time warnings yet. See https://gitlab.com/-/snippets/1929968
class CheckRubySyntax
VALID_RUBYFILES = %w[Rakefile Dangerfile Gemfile Guardfile].to_set.freeze
attr_reader :files
def initialize(files)
@files = files
end
def ruby_files
@ruby_files ||=
@files.select do |file|
file.end_with?(".rb") || VALID_RUBYFILES.include?(File.basename(file))
end
end
def run
ruby_files.filter_map do |file|
check_ruby(file)
end
end
private
def check_ruby(file)
RubyVM::InstructionSequence.compile(File.open(file), file)
nil
rescue SyntaxError => e
e
end
end
end