Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-11-20 18:23:23 +00:00
parent 3d53332cde
commit 40ea82e97a
53 changed files with 500 additions and 151 deletions

View File

@ -2699,6 +2699,8 @@
when: never
- if: '$DEPENDENCY_SCANNING_DISABLED || $GITLAB_FEATURES !~ /\bdependency_scanning\b/ || $DS_EXCLUDED_ANALYZERS =~ /gemnasium([^-]|$)/'
when: never
# Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/361657 is resolved
- <<: *if-default-branch-refs
- <<: *if-default-refs
changes: *dependency-patterns
@ -2708,6 +2710,8 @@
when: never
- if: '$DEPENDENCY_SCANNING_DISABLED || $GITLAB_FEATURES !~ /\bdependency_scanning\b/ || $DS_EXCLUDED_ANALYZERS =~ /gemnasium-python/'
when: never
# Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/361657 is resolved
- <<: *if-default-branch-refs
- <<: *if-default-refs
changes: *python-patterns

View File

@ -290,7 +290,6 @@ RSpec/ExampleWithoutDescription:
- 'spec/initializers/gitlab_http_spec.rb'
- 'spec/initializers/google_cloud_profiler_spec.rb'
- 'spec/keeps/helpers/postgres_ai_spec.rb'
- 'spec/lib/api/entities/virtual_registries/packages/maven/cached_response_spec.rb'
- 'spec/lib/banzai/filter/commit_trailers_filter_spec.rb'
- 'spec/lib/banzai/pipeline/incident_management/timeline_event_pipeline_spec.rb'
- 'spec/lib/banzai/pipeline_spec.rb'
@ -477,7 +476,6 @@ RSpec/ExampleWithoutDescription:
- 'spec/models/users/banned_user_spec.rb'
- 'spec/models/users/phone_number_validation_spec.rb'
- 'spec/models/users/project_callout_spec.rb'
- 'spec/models/virtual_registries/packages/maven/cached_response_spec.rb'
- 'spec/models/virtual_registries/packages/maven/registry_spec.rb'
- 'spec/models/virtual_registries/packages/maven/registry_upstream_spec.rb'
- 'spec/models/virtual_registries/packages/maven/upstream_spec.rb'

View File

@ -113,6 +113,7 @@ export default {
class="!gl-text-subtle"
:aria-expanded="isExpanded.toString()"
:aria-controls="$options.ariaControlsId"
data-testid="toggle-button"
@click="toggleWidget"
>
<gl-icon :name="iconName" class="gl-mr-2" />
@ -126,6 +127,15 @@ export default {
{{ failedJobsCountBadge }}
</gl-badge>
</template>
<template #actions>
<gl-button
v-if="isExpanded"
href="https://gitlab.com/gitlab-org/gitlab/-/issues/502436"
data-testid="feedback-button"
>
{{ __('Leave feedback') }}
</gl-button>
</template>
<failed-jobs-list
v-if="isExpanded"
:is-maximum-job-limit-reached="isMaximumJobLimitReached"

View File

@ -91,7 +91,7 @@ export default {
@primary="onSubmit"
>
<template #modal-title>
<gl-sprintf :message="s__('Environments|Stopping %{environmentName}')">
<gl-sprintf :message="s__('Environments|Stop %{environmentName}')">
<template #environmentName>
<span v-gl-tooltip :title="environment.name" class="gl-grow gl-truncate">
{{ environment.name }}?

View File

@ -392,6 +392,7 @@ class GfmAutoComplete {
UNASSIGN_REVIEWER: '/unassign_reviewer',
REASSIGN: '/reassign',
CC: '/cc',
REQUEST_REVIEW: '/request_review',
};
let assignees = [];
let reviewers = [];

View File

@ -709,6 +709,7 @@ export default {
:sort-options="sortOptions"
:initial-sort-by="sortKey"
:issuables="mergeRequests"
issuable-symbol="!"
:error="mergeRequestsError"
:tabs="$options.mergeRequestListTabs"
:current-tab="state"

View File

@ -231,6 +231,7 @@ export default {
category="tertiary"
type="reset"
class="sidebar-collapsed-icon sidebar-collapsed-container !gl-rounded-none !gl-shadow-none"
:class="{ '!gl-text-blue-500': hasTodo }"
@click.stop.prevent="toggleTodo"
>
<gl-animated-todo-icon :is-on="hasTodo" />

View File

@ -159,7 +159,7 @@ export default {
>
<template #list-item="{ item }">
<strong class="gl-block gl-w-full">{{ item.text }}</strong>
<gl-truncate class="gl-mt-2" :text="item.content" position="end" />
<gl-truncate class="gl-mt-2 gl-text-subtle" :text="item.content" position="end" />
</template>
</gl-disclosure-dropdown-group>
</ul>

View File

@ -99,6 +99,10 @@
.comment-templates-modal {
padding: 3rem 0.5rem 0;
.modal-content {
@apply gl-max-h-[80vh];
}
// stylelint-disable-next-line gitlab/no-gl-class
&.gl-modal .modal-dialog {
align-items: flex-start;

View File

@ -6,17 +6,22 @@ module Integrations
field :webhook,
section: SECTION_TYPE_CONNECTION,
help: 'https://yourcircuit.com/rest/v2/webhooks/incoming/…',
help: -> { _('The Unify Circuit webhook (for example, `https://circuit.com/rest/v2/webhooks/incoming/...`).') },
required: true
field :notify_only_broken_pipelines,
type: :checkbox,
description: -> { _('Send notifications for broken pipelines.') },
section: SECTION_TYPE_CONFIGURATION
field :branches_to_be_notified,
type: :select,
section: SECTION_TYPE_CONFIGURATION,
title: -> { s_('Integrations|Branches for which notifications are to be sent') },
description: -> {
_('Branches to send notifications for. Valid options are `all`, `default`, `protected`, ' \
'and `default_and_protected`. The default value is `default`.')
},
choices: -> { branch_choices }
def self.title

View File

@ -7,16 +7,16 @@ module Packages
include ShaAttribute
include Packages::Destructible
# Used in destroying stale symbols in worker
# Used in destroying orphan symbols in worker
enum :status, default: 0, processing: 1, error: 3
belongs_to :package, class_name: 'Packages::Nuget::Package', inverse_of: :nuget_symbols
belongs_to :project
delegate :project_id, :project, to: :package
delegate :project_id, :project, to: :package, allow_nil: true
validates :file, :file_path, :signature, :object_storage_key, :size, presence: true
validates :signature, uniqueness: { scope: :file_path }
validates :signature, uniqueness: { scope: %i[file_path package_id] }, if: -> { package }
validates :object_storage_key, uniqueness: true
validates :package, presence: true
@ -26,8 +26,8 @@ module Packages
before_validation :set_object_storage_key, on: :create
scope :stale, -> { where(package_id: nil) }
scope :pending_destruction, -> { stale.default }
scope :orphan, -> { where(package_id: nil) }
scope :pending_destruction, -> { orphan.default }
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: Array.wrap(checksums).map(&:downcase)) }
@ -36,6 +36,7 @@ module Packages
with_signature(signature)
.with_file_name(file_name)
.with_file_sha256(checksums)
.where.not(orphan.where_values_hash)
.take
end

View File

@ -19,6 +19,7 @@ module VirtualRegistries
enum :status, default: 0, processing: 1, pending_destruction: 2, error: 3
ignore_column :downloads_count, remove_with: '17.8', remove_after: '2024-12-23'
ignore_column :downloaded_at, remove_with: '17.9', remove_after: '2025-01-23'
validates :group, top_level_group: true, presence: true
validates :relative_path,
@ -86,13 +87,6 @@ module VirtualRegistries
(upstream_checked_at + upstream.cache_validity_hours.hours).past?
end
def bump_statistics(include_upstream_checked_at: false)
now = Time.zone.now
updates = { downloaded_at: now }
updates[:upstream_checked_at] = now if include_upstream_checked_at
update_columns(**updates)
end
private
def set_object_storage_key

View File

@ -10,7 +10,8 @@ module Import
def initialize(import_source_user)
@import_source_user = import_source_user
@reassigned_by_user = User.find_by_id(import_source_user.reassigned_by_user_id)
@reassigned_by_user = import_source_user.reassigned_by_user
@project_membership_created = false
end
def execute
@ -24,6 +25,8 @@ module Import
create_memberships
delete_placeholder_memberships
UserProjectAccessChangedService.new(import_source_user.reassign_to_user_id).execute if project_membership_created?
import_source_user.complete!
end
@ -153,6 +156,8 @@ module Import
)
member.save!
@project_membership_created = true if memberable.is_a?(Project)
rescue ActiveRecord::ActiveRecordError => exception
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
exception,
@ -193,6 +198,10 @@ module Import
Import::Placeholders::Membership.by_source_user(import_source_user)
end
def project_membership_created?
@project_membership_created == true
end
def log_create_membership_skipped(message, placeholder_membership, existing_membership)
log_info(
message,

View File

@ -4,7 +4,9 @@ module Notes
class CreateService < ::Notes::BaseService
include IncidentManagement::UsageData
def execute(skip_capture_diff_note_position: false, skip_merge_status_trigger: false, executing_user: nil)
def execute(
skip_capture_diff_note_position: false, skip_merge_status_trigger: false, executing_user: nil,
importing: false)
Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
%w[
notes
@ -29,7 +31,7 @@ module Notes
execute_quick_actions(note) do |only_commands|
note.check_for_spam(action: :create, user: current_user) if check_for_spam?(only_commands)
after_commit(note)
after_commit(note) unless importing
note_saved = note.with_transaction_returning_status do
break false if only_commands

View File

@ -29,7 +29,6 @@ module VirtualRegistries
file: file,
size: file.size,
file_sha1: file.sha1,
downloaded_at: now,
content_type: content_type
}
updates[:file_md5] = file.md5 unless Gitlab::FIPS.enabled?

View File

@ -65,11 +65,8 @@ module VirtualRegistries
def cache_response_still_valid?
return false unless cached_response
return true unless cached_response.stale?
unless cached_response.stale?
cached_response.bump_statistics
return true
end
# cached response with no etag can't be checked
return false if cached_response.upstream_etag.blank?
@ -77,7 +74,7 @@ module VirtualRegistries
return false unless cached_response.upstream_etag == response.headers['etag']
cached_response.bump_statistics(include_upstream_checked_at: true)
cached_response.update_column(:upstream_checked_at, Time.current)
true
end

View File

@ -0,0 +1,33 @@
# frozen_string_literal: true
class UpdateUniqueIndexOnPackagesNugetSymbol < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.7'
TABLE_NAME = :packages_nuget_symbols
OLD_INDEX_NAME = :index_packages_nuget_symbols_on_signature_and_file_path
NEW_INDEX_NAME = :idx_pkgs_nuget_symbols_on_signature_and_file_path_with_pkg_id
def up
add_concurrent_index(
TABLE_NAME,
%i[signature file_path],
unique: true,
name: NEW_INDEX_NAME,
where: 'package_id IS NOT NULL'
)
remove_concurrent_index_by_name(TABLE_NAME, OLD_INDEX_NAME)
end
def down
add_concurrent_index(
TABLE_NAME,
%i[signature file_path],
unique: true,
name: OLD_INDEX_NAME
)
remove_concurrent_index_by_name(TABLE_NAME, NEW_INDEX_NAME)
end
end

View File

@ -0,0 +1 @@
da65c2c8c0afc61af3000cdf6fe11ddaf61e157b6b73f0b274d825b4adf2d43b

View File

@ -28515,6 +28515,8 @@ CREATE INDEX idx_pkgs_npm_metadata_caches_on_id_and_project_id_and_status ON pac
CREATE INDEX idx_pkgs_nuget_symbols_on_lowercase_signature_and_file_name ON packages_nuget_symbols USING btree (lower(signature), lower(file));
CREATE UNIQUE INDEX idx_pkgs_nuget_symbols_on_signature_and_file_path_with_pkg_id ON packages_nuget_symbols USING btree (signature, file_path) WHERE (package_id IS NOT NULL);
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_pkgs_project_id_lower_name_when_nuget_installable_version ON packages_packages USING btree (project_id, lower((name)::text)) WHERE ((package_type = 4) AND (version IS NOT NULL) AND (status = ANY (ARRAY[0, 1])));
@ -31329,8 +31331,6 @@ CREATE INDEX index_packages_nuget_symbols_on_package_id ON packages_nuget_symbol
CREATE INDEX index_packages_nuget_symbols_on_project_id ON packages_nuget_symbols USING btree (project_id);
CREATE UNIQUE INDEX index_packages_nuget_symbols_on_signature_and_file_path ON packages_nuget_symbols USING btree (signature, file_path);
CREATE INDEX index_packages_on_available_pypi_packages ON packages_packages USING btree (project_id, id) WHERE ((status = ANY (ARRAY[0, 1])) AND (package_type = 5) AND (version IS NOT NULL));
CREATE INDEX index_packages_package_file_build_infos_on_package_file_id ON packages_package_file_build_infos USING btree (package_file_id);

View File

@ -48,3 +48,4 @@ Customize and configure your self-managed GitLab installation.
- [Snippets](../administration/snippets/index.md)
- [Host the product documentation](../administration/docs_self_host.md)
- [Custom HTML header tags](../administration/custom_html_header_tags.md)
- [Self-hosted models](../administration/self_hosted_models/index.md)

View File

@ -12,7 +12,8 @@ Learn how to administer a self-managed GitLab instance.
| | | |
|--|--|--|
| [**Get started**](../administration/get_started.md)<br>Administration overview. | [**All feature flags**](../user/feature_flags.md)<br>Complete list of flags. | [**Authentication and authorization**](../administration/auth/index.md)<br>Third-party authentication providers. |
| [**Configure your installation**](../administration/configure.md)<br>Installation settings. | [**Update your Admin area settings**](../administration/settings/index.md)<br>Product settings. | [**Configure GitLab Dedicated**](../administration/dedicated/index.md)<br>IP allowlists, SAML, maintenance. |
| [**Maintain your installation**](../administration/operations/index.md)<br>Backup and restore, move repos, maintenance tasks. | [**Secure your application**](../user/application_security/secure_your_application.md)<br>SSH key limits, 2FA, tokens, hardening. | [**Administer users**](../user/profile/account/create_accounts.md)<br>Passwords, user moderation, broadcast messages. |
| [**Configure GitLab**](../administration/configure.md)<br>Installation settings. | [**Update your Admin area settings**](../administration/settings/index.md)<br>Product settings. | [**Maintain GitLab**](../administration/operations/index.md)<br>Backup and restore, move repositories, maintenance tasks. |
| [**Monitor GitLab**](../administration/monitoring/index.md)<br>Performance, health, uptime monitoring. | [**Secure GitLab**](../security/index.md)<br>SSH key limits, 2FA, tokens, hardening. | [**Administer users**](../user/profile/account/create_accounts.md)<br>Passwords, user moderation, broadcast messages. |
| [**GitLab Dedicated**](../administration/dedicated/index.md)<br>Get started with GitLab Dedicated. | | |
Only GitLab team members have access to administration tools and settings on GitLab.com.

View File

@ -1,6 +1,7 @@
---
stage: Monitor
group: Platform Insights
description: Performance, health, uptime monitoring.
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
---

View File

@ -20959,6 +20959,7 @@ Represents a ComplianceFramework associated with a Project.
| <a id="complianceframeworkprojects"></a>`projects` | [`ProjectConnection`](#projectconnection) | Projects associated with the compliance framework. (see [Connections](#connections)) |
| <a id="complianceframeworkscanexecutionpolicies"></a>`scanExecutionPolicies` | [`ScanExecutionPolicyConnection`](#scanexecutionpolicyconnection) | Scan Execution Policies of the compliance framework. (see [Connections](#connections)) |
| <a id="complianceframeworkscanresultpolicies"></a>`scanResultPolicies` | [`ScanResultPolicyConnection`](#scanresultpolicyconnection) | Scan Result Policies of the compliance framework. (see [Connections](#connections)) |
| <a id="complianceframeworkvulnerabilitymanagementpolicies"></a>`vulnerabilityManagementPolicies` | [`VulnerabilityManagementPolicyConnection`](#vulnerabilitymanagementpolicyconnection) | Vulnerability Management Policies of the compliance framework. (see [Connections](#connections)) |
### `ComplianceRequirement`
@ -25649,6 +25650,27 @@ Returns [`[VulnerableProjectsByGrade!]`](#vulnerableprojectsbygrade).
| <a id="groupvulnerabilitygradesincludesubgroups"></a>`includeSubgroups` | [`Boolean`](#boolean) | Include grades belonging to subgroups. |
| <a id="groupvulnerabilitygradeslettergrade"></a>`letterGrade` | [`VulnerabilityGrade`](#vulnerabilitygrade) | Filter the response by given letter grade. |
##### `Group.vulnerabilityManagementPolicies`
Vulnerability Management Policies of the project.
DETAILS:
**Introduced** in GitLab 17.7.
**Status**: Experiment.
Returns [`VulnerabilityManagementPolicyConnection`](#vulnerabilitymanagementpolicyconnection).
This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#pagination-arguments):
`before: String`, `after: String`, `first: Int`, and `last: Int`.
###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="groupvulnerabilitymanagementpoliciesincludeunscoped"></a>`includeUnscoped` | [`Boolean`](#boolean) | Filter policies that are scoped to the project. |
| <a id="groupvulnerabilitymanagementpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
##### `Group.vulnerabilitySeveritiesCount`
Counts for each vulnerability severity in the group and its subgroups.
@ -29477,6 +29499,27 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="namespacescanresultpoliciesincludeunscoped"></a>`includeUnscoped` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in GitLab 17.3. **Status**: Experiment. Filter policies that are scoped to the project. |
| <a id="namespacescanresultpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
##### `Namespace.vulnerabilityManagementPolicies`
Vulnerability Management Policies of the project.
DETAILS:
**Introduced** in GitLab 17.7.
**Status**: Experiment.
Returns [`VulnerabilityManagementPolicyConnection`](#vulnerabilitymanagementpolicyconnection).
This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#pagination-arguments):
`before: String`, `after: String`, `first: Int`, and `last: Int`.
###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="namespacevulnerabilitymanagementpoliciesincludeunscoped"></a>`includeUnscoped` | [`Boolean`](#boolean) | Filter policies that are scoped to the project. |
| <a id="namespacevulnerabilitymanagementpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
##### `Namespace.workItem`
Find a work item by IID directly associated with the namespace(project or group). Returns `null` for group level work items if the `namespace_level_work_items` feature flag is disabled.

View File

@ -15,12 +15,12 @@ shows the status of its most recent pipeline, or shows **No pipeline** if a pipe
Possible statuses include:
- **Pipeline canceled**
- **Pipeline failed**
- **Pipeline passed**
- **Pipeline pending**
- **Pipeline running**
- **Pipeline skipped**
- Pipeline canceled
- Pipeline failed
- Pipeline passed
- Pipeline pending
- Pipeline running
- Pipeline skipped
## View pipeline information
@ -91,7 +91,15 @@ VS Code opens a new tab (`.gitlab-ci (Merged).yml`) with full information.
### CI/CD variable autocompletion
Quickly find the CI/CD variable you are looking for with the CI/CD variable autocompletion:
Quickly find the CI/CD variable you are looking for with the CI/CD variable autocompletion.
Prerequisites:
- Your file is named either:
- `.gitlab-ci.yml`.
- Beginning with `.gitlab-ci` and ending with `.yml` or `.yaml`, like `.gitlab-ci.production.yml`.
To autocomplete a variable:
1. In VS Code, open your `.gitlab-ci.yml` file, and ensure the file's tab is in focus.
1. Begin entering the name of a variable to display auto-complete options.

View File

@ -198,18 +198,62 @@ To view issues and merge requests for a specific project:
- All project merge requests
- Your [custom queries](custom_queries.md)
1. Select an issue or merge request to open it in a new VS Code tab.
1. Optional. If you select a merge request, its sidebar entry expands to show all files changed
in the merge request. Deleted files are marked in red. For example:
Select an issue or merge request to open it in a new VS Code tab.
## Review a merge request
Use this extension to review, comment on, and approve merge requests without leaving VS Code:
1. While viewing [issues and merge requests](#view-issues-and-merge-requests) in VS Code, select the
merge request you want to review. Its sidebar entry expands with more information.
1. Under the merge request's number and title, select **Description** to read more about the merge request.
1. To review the proposed changes to a file, select the file from the list to show it in a VS Code tab.
Diff comments are shown inline in the tab. In the list, deleted files are marked in red:
![An alphabetical list of files changed in this merge request, including the type of changes.](../img/vscode_view_changed_file_v17_6.png)
1. Select a file to view its diff in a VS Code tab.
Use the diff to:
- Review and create discussions.
- Resolve and unresolve these discussions.
- Delete and edit individual comments.
### Compare with default branch
<!-- vale gitlab_base.InclusiveLanguage = NO -->
To compare your branch with your project's default branch, without creating a merge request:
1. Open the Command Palette:
- For macOS, press <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>.
- For Windows or Linux, press <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>.
1. In the Command Palette, search for **GitLab: Compare current branch with master** and press <kbd>Enter</kbd>.
The extension opens a new browser tab. It shows a diff between the most recent commit on your branch, and
the most recent commit on your project's default branch.
<!-- vale gitlab_base.InclusiveLanguage = YES -->
### Open current file in GitLab UI
To open a file from your current GitLab project in the GitLab UI, with specific lines highlighted:
1. Open your desired file in VS Code.
1. Select the lines you want to highlight.
1. Open the Command Palette:
- For macOS, press <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>.
- For Windows or Linux, press <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>.
1. In the Command Palette, search for **GitLab: Open active file on GitLab** and press <kbd>Enter</kbd>.
## View security findings
DETAILS:
**Tier:** Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
Prerequisites:
- You're using GitLab Workflow version 3.74.0 or later.
- Your project includes [Security Risk Management](https://about.gitlab.com/features/?stage=secure) features, such as
Static Application Security Testing (SAST), Dynamic Application Security Testing (DAST),
Container Scanning, or Dependency Scanning.

View File

@ -64,7 +64,7 @@ Prerequisites:
| `gitlab.certKey`| null | Unsupported. See [epic 6244](https://gitlab.com/groups/gitlab-org/-/epics/6244). If your self-managed GitLab instance requires a custom certificate or key pair, set this option to point to your certificate key file. See `gitlab.cert`. |
| `gitlab.ignoreCertificateErrors` | false | Unsupported. See [epic 6244](https://gitlab.com/groups/gitlab-org/-/epics/6244). If you use a self-managed GitLab instance with no SSL certificate, or have certificate issues that prevent you from using the extension, set this option to `true` to ignore certificate errors. |
## Disable code suggestions
## Disable Code Suggestions
Code completion is enabled by default. To disable it:
@ -193,3 +193,15 @@ A workaround exists for Ubuntu users who use versions of VS Code earlier than 1.
If you use VS Code version 1.68.0 or later, re-installation might not be possible. However, you can still run
the last three steps to re-authenticate.
## Set token with environment variables
If you often delete your VS Code storage, such as in Gitpod containers, you can create environment variables
before starting VS Code. If you set the token in a
[VS Code environment variable](https://code.visualstudio.com/docs/editor/variables-reference#_environment-variables),
you don't have to set a personal access token each time you delete your VS Code storage. Set these variables:
- `GITLAB_WORKFLOW_INSTANCE_URL`: Your GitLab instance URL, like `https://gitlab.com`.
- `GITLAB_WORKFLOW_TOKEN`: Your personal access token, which you created [during setup](https://gitlab.com/gitlab-org/gitlab-vscode-extension/#setup).
The token configured in an environment variable is overridden if you configure a token for the same GitLab instance in the extension.

View File

@ -11,15 +11,11 @@ DETAILS:
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
There's no automatic removal process for blobs. Unless you delete them manually, they're stored
indefinitely. Since this impacts your
[storage usage quota](../../storage_usage_quotas.md),
it's important that you clear unused items from the cache. This page covers several options for
doing so.
indefinitely. This page covers several options for clearing unused items from the cache.
## Check Dependency Proxy Storage Use
The Usage Quotas page (**Settings > Usage Quotas > Storage**) displays storage usage for Packages, which includes the Dependency Proxy,
however, the storage is not yet displayed.
The [**Usage Quotas**](../../storage_usage_quotas.md) page displays storage usage for the dependency proxy.
## Use the API to clear the cache

View File

@ -204,35 +204,31 @@ Replace `@scope` with your package's scope.
### For installing packages
When installing packages, you can use project, group, or instance endpoints. The URL structure varies accordingly:
You can configure these URLs using one of the following methods:
When you install packages, you can use project, group, or instance endpoints. The URL structure varies accordingly.
To configure these URLs, use one of these methods:
::Tabs
:::TabTitle `.npmrc` file
:::TabTitle `.npmrc` file
Create or edit the `.npmrc` file in your project root. Use the appropriate URL based on your needs:
- For a project:
```shell
npm config set @scope:registry=https://gitlab.example.com/api/v4/projects/<project_id>/packages/npm/
@scope:registry=https://gitlab.example.com/api/v4/projects/<project_id>/packages/npm/
```
- For a group:
```shell
npm config set @scope:registry=https://gitlab.example.com/api/v4/groups/<group_id>/-/packages/npm/
@scope:registry=https://gitlab.example.com/api/v4/groups/<group_id>/-/packages/npm/
```
- For an instance:
```shell
npm config set @scope:registry=https://gitlab.example.com/api/v4/packages/npm/
@scope:registry=https://gitlab.example.com/api/v4/packages/npm/
```
:::TabTitle `npm config`

View File

@ -57,8 +57,8 @@ To auto-format this table, use the VS Code Markdown Table formatter: `https://do
| `/approve` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Approve the merge request. |
| `/assign @user1 @user2` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Assign one or more users. |
| `/assign me` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Assign yourself. |
| `/assign_reviewer @user1 @user2` or `/reviewer @user1 @user2` or `/request_review @user1 @user2` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Assign one or more users as reviewers. |
| `/assign_reviewer me` or `/reviewer me` or `/request_review me` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Assign yourself as a reviewer. |
| `/assign_reviewer @user1 @user2` or `/reviewer @user1 @user2` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Assign one or more users as reviewers. |
| `/assign_reviewer me` or `/reviewer me` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Assign yourself as a reviewer. |
| `/blocked_by <issue1> <issue2>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Mark the issue as blocked by other issues. The `<issue>` value should be in the format of `#issue`, `group/project#issue`, or the full issue URL. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214232) in GitLab 16.0). |
| `/blocks <issue1> <issue2>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Mark the issue as blocking other issues. The `<issue>` value should be in the format of `#issue`, `group/project#issue`, or the full issue URL. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214232) in GitLab 16.0). |
| `/cc @user` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Mention a user. This command performs no action. You can instead type `CC @user` or only `@user`. |
@ -112,6 +112,8 @@ To auto-format this table, use the VS Code Markdown Table formatter: `https://do
| `/remove_time_spent` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Remove time spent. |
| `/remove_zoom` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Remove Zoom meeting from this issue. |
| `/reopen` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Reopen. |
| `/request_review @user1 @user2` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Assigns or requests a new review from one or more users. |
| `/request_review me` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Assigns or requests a new review from one or more users. |
| `/severity <severity>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set the severity. Issue type must be `Incident`. Options for `<severity>` are `S1` ... `S4`, `critical`, `high`, `medium`, `low`, `unknown`. |
| `/shrug` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Add `¯\_(ツ)_/¯`. |
| `/spend <time> [<date>]` or `/spend_time <time> [<date>]` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Add or subtract spent time. Optionally, specify the date that time was spent on. For example, `/spend 1mo 2w 3d 4h 5m 2018-08-26` or `/spend -1h 30m`. For more information, see [Time tracking](time_tracking.md). Alias `/spend_time` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16501) in GitLab 15.6. |

View File

@ -45,6 +45,7 @@ To set up infrastructure for workspaces:
> - **Git reference** and **Devfile location** [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/392382) in GitLab 16.10.
> - **Time before automatic termination** [renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/392382) to **Workspace automatically terminates after** in GitLab 16.10.
> - **Variables** [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/463514) in GitLab 17.1.
> - **Workspace automatically terminates after** [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166065) in GitLab 17.6.
Prerequisites:
@ -65,8 +66,6 @@ To create a workspace:
GitLab uses to create the workspace.
1. In **Devfile location**, enter the path to the devfile you use to configure the workspace.
If your devfile is not in the root directory of your project, specify a relative path.
1. In **Workspace automatically terminates after**, enter the number of hours until the workspace automatically terminates.
This timeout is a safety measure to prevent a workspace from consuming excessive resources or running indefinitely.
1. In **Variables**, enter the keys and values of the environment variables you want to inject into the workspace.
To add a new variable, select **Add variable**.
1. Select **Create workspace**.

View File

@ -17,7 +17,6 @@ module API
:file_md5,
:file_sha1,
:size,
:downloaded_at,
:relative_path,
:upstream_etag,
:content_type,

View File

@ -428,14 +428,7 @@ module API
}
],
'telegram' => ::Integrations::Telegram.api_arguments,
'unify-circuit' => [
{
required: true,
name: :webhook,
type: String,
desc: 'The Unify Circuit webhook. e.g. https://circuit.com/rest/v2/webhooks/incoming/…'
}
].flatten,
'unify-circuit' => ::Integrations::UnifyCircuit.api_arguments,
'webex-teams' => ::Integrations::WebexTeams.api_arguments,
'zentao' => [
{

View File

@ -91,6 +91,8 @@ module Gitlab
rescue Timeout::Error => e
class_name = name.demodulize
Gitlab::ErrorTracking.track_exception(e, project_id: context[:project]&.id, class_name: class_name)
input
end
end
end

View File

@ -270,7 +270,9 @@ module Gitlab
def parent_ids
return @parent_ids unless @lazy_load_parents
@parent_ids ||= @repository.commit(id).parent_ids
@parent_ids = @repository.commit(id).parent_ids if @parent_ids.nil? || @parent_ids.empty?
@parent_ids
end
def parent_id

View File

@ -74,7 +74,8 @@ module Gitlab
line_code: note.line_code,
created_at: note.created_at,
updated_at: note.updated_at,
st_diff: note.diff_hash.to_yaml
st_diff: note.diff_hash.to_yaml,
imported_from: ::Import::HasImportSource::IMPORT_SOURCES[:github]
}
diff_note = LegacyDiffNote.new(attributes.merge(importing: true))
@ -102,8 +103,9 @@ module Gitlab
commit_id: note.original_commit_id,
created_at: note.created_at,
updated_at: note.updated_at,
position: note.diff_position
}).execute
position: note.diff_position,
imported_from: ::Import::SOURCE_GITHUB
}).execute(importing: true)
raise DiffNoteCreationError, record unless record.persisted?

View File

@ -314,7 +314,7 @@ module Gitlab
parse_params do |reviewer_param|
extract_users(reviewer_param)
end
command :assign_reviewer, :reviewer, :request_review do |users|
command :assign_reviewer, :reviewer do |users|
next if users.empty?
if quick_action_target.allows_multiple_reviewers?
@ -325,6 +325,54 @@ module Gitlab
end
end
########################################################################
#
# /request_review
#
desc do
_('Request a review')
end
explanation do |users|
_('Requests a review from %{reviewer_users_sentence}.') % { reviewer_users_sentence: reviewer_users_sentence(users) }
end
execution_message do |users = nil|
if users.blank?
_("Failed to request a review because no user was specified.")
else
_('Requested a review from %{reviewer_users_sentence}.') % { reviewer_users_sentence: reviewer_users_sentence(users) }
end
end
params do
quick_action_target.allows_multiple_reviewers? ? '@user1 @user2' : '@user'
end
types MergeRequest
condition do
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
end
parse_params do |reviewer_param|
extract_users(reviewer_param)
end
command :request_review do |users|
next if users.empty?
@updates[:reviewer_ids] ||= quick_action_target.reviewers.map(&:id)
service = ::MergeRequests::RequestReviewService.new(
project: quick_action_target.project,
current_user: current_user
)
reviewers_to_add(users).each do |user|
if @updates[:reviewer_ids].include?(user.id)
# Request a new review from the reviewer if they are already assigned
service.execute(quick_action_target, user)
else
# Assign the user as a reviewer if they are not already
@updates[:reviewer_ids] << user.id
end
end
end
########################################################################
#
# /unassign_reviewer

View File

@ -21798,6 +21798,9 @@ msgstr ""
msgid "Environments|Stop"
msgstr ""
msgid "Environments|Stop %{environmentName}"
msgstr ""
msgid "Environments|Stop environment"
msgstr ""
@ -21807,9 +21810,6 @@ msgstr ""
msgid "Environments|Stop unused environments"
msgstr ""
msgid "Environments|Stopping %{environmentName}"
msgstr ""
msgid "Environments|Synced"
msgstr ""
@ -23269,6 +23269,9 @@ msgstr ""
msgid "Failed to remove user key."
msgstr ""
msgid "Failed to request a review because no user was specified."
msgstr ""
msgid "Failed to retrieve page"
msgstr ""
@ -46514,6 +46517,9 @@ msgstr ""
msgid "Request a new one"
msgstr ""
msgid "Request a review"
msgstr ""
msgid "Request changes"
msgstr ""
@ -46547,6 +46553,9 @@ msgstr ""
msgid "Requested %{time_ago}"
msgstr ""
msgid "Requested a review from %{reviewer_users_sentence}."
msgstr ""
msgid "Requested design version does not exist."
msgstr ""
@ -46562,6 +46571,9 @@ msgstr ""
msgid "Requests a Duo Code Review"
msgstr ""
msgid "Requests a review from %{reviewer_users_sentence}."
msgstr ""
msgid "Requests for pages at %{code_start}%{help_text_url}%{code_end} redirect to the URL. The destination must meet certain requirements. %{docs_link_start}Learn more%{docs_link_end}."
msgstr ""
@ -55253,6 +55265,9 @@ msgstr ""
msgid "The URLs for connecting to Elasticsearch. For clustering, add the URLs separated by commas."
msgstr ""
msgid "The Unify Circuit webhook (for example, `https://circuit.com/rest/v2/webhooks/incoming/...`)."
msgstr ""
msgid "The XML file must be less than %{max_size} MB."
msgstr ""

View File

@ -7,6 +7,7 @@ FactoryBot.define do
size { 100.bytes }
sequence(:signature) { |n| "b91a152048fc4b3883bf3cf73fbc03f#{n}FFFFFFFF" }
file_sha256 { 'dd1aaf26c557685cc37f93f53a2b6befb2c2e679f5ace6ec7a26d12086f358be' }
project_id { package.project_id }
transient do
file_fixture { 'spec/fixtures/packages/nuget/symbol/package.pdb' }
@ -16,7 +17,7 @@ FactoryBot.define do
symbol.file = fixture_file_upload(evaluator.file_fixture)
end
trait :stale do
trait :orphan do
after(:create) do |entry|
entry.update_attribute(:package_id, nil)
end

View File

@ -1,4 +1,4 @@
import { GlBadge, GlButton } from '@gitlab/ui';
import { GlBadge } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
@ -51,10 +51,11 @@ describe('PipelineFailedJobsWidget component', () => {
});
};
const findFailedJobsButton = () => wrapper.findComponent(GlButton);
const findFailedJobsButton = () => wrapper.findByTestId('toggle-button');
const findFailedJobsList = () => wrapper.findComponent(FailedJobsList);
const findCrudComponent = () => wrapper.findComponent(CrudComponent);
const findCount = () => wrapper.findComponent(GlBadge);
const findFeedbackButton = () => wrapper.findByTestId('feedback-button');
describe('when there are failed jobs', () => {
beforeEach(async () => {
@ -93,6 +94,10 @@ describe('PipelineFailedJobsWidget component', () => {
it('the failed jobs button has the correct "aria-expanded" attribute value', () => {
expect(findFailedJobsButton().attributes('aria-expanded')).toBe('true');
});
it('displays feedback button', () => {
expect(findFeedbackButton().exists()).toBe(true);
});
});
describe('when the job details are not expanded', () => {
@ -107,6 +112,10 @@ describe('PipelineFailedJobsWidget component', () => {
it('the failed jobs button has the correct "aria-expanded" attribute value', () => {
expect(findFailedJobsButton().attributes('aria-expanded')).toBe('false');
});
it('does not display feedback button', () => {
expect(findFeedbackButton().exists()).toBe(false);
});
});
describe('"aria-controls" attribute', () => {

View File

@ -123,6 +123,7 @@ describe('Merge requests list app', () => {
recentSearchesStorageKey: 'merge_requests',
sortOptions: getSortOptions({ hasManualSort: false }),
initialSortBy: 'CREATED_DESC',
issuableSymbol: '!',
issuables: getQueryResponse.data.project.mergeRequests.nodes,
tabs: mergeRequestListTabs,
currentTab: 'opened',

View File

@ -7,8 +7,8 @@ RSpec.describe API::Entities::VirtualRegistries::Packages::Maven::CachedResponse
subject { described_class.new(cached_response).as_json }
it do
it 'has the expected attributes' do
is_expected.to include(:cached_response_id, :group_id, :upstream_id, :upstream_checked_at, :created_at, :updated_at,
:file, :file_md5, :file_sha1, :size, :downloaded_at, :relative_path, :upstream_etag, :content_type)
:file, :file_md5, :file_sha1, :size, :relative_path, :upstream_etag, :content_type)
end
end

View File

@ -987,9 +987,9 @@ module Gitlab
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
instance_of(Timeout::Error),
project_id: context[:project].id, class_name: described_class.name.demodulize
)
).and_call_original
render('<b>ascii</b>', context)
expect(render('<b>ascii</b>', context)).to eq '<b>ascii</b>'
end
end

View File

@ -52,6 +52,7 @@ RSpec.describe Gitlab::GithubImport::Importer::DiffNoteImporter, :aggregate_fail
note = project.notes.diff_notes.take
expect(note).to be_valid
expect(note.imported_from).to eq(::Import::SOURCE_GITHUB.to_s)
expect(note.author_id).to eq(user.id)
expect(note.commit_id).to eq('original123abc')
expect(note.created_at).to eq(created_at)
@ -160,12 +161,18 @@ RSpec.describe Gitlab::GithubImport::Importer::DiffNoteImporter, :aggregate_fail
end
it 'imports the note as diff note' do
expect_next_instance_of(Import::Github::Notes::CreateService) do |service|
expect(service).to receive(:execute).with(importing: true).and_call_original
end
expect { subject.execute }
.to change(DiffNote, :count)
.by(1)
.and not_change(LegacyDiffNote, :count)
note = project.notes.diff_notes.take
expect(note).to be_valid
expect(note.imported_from).to eq(::Import::SOURCE_GITHUB.to_s)
expect(note.noteable_type).to eq('MergeRequest')
expect(note.noteable_id).to eq(merge_request.id)
expect(note.project_id).to eq(project.id)
@ -313,12 +320,17 @@ RSpec.describe Gitlab::GithubImport::Importer::DiffNoteImporter, :aggregate_fail
end
it 'imports the note as diff note' do
expect_next_instance_of(Import::Github::Notes::CreateService) do |service|
expect(service).to receive(:execute).with(importing: true).and_call_original
end
expect { subject.execute }
.to change(DiffNote, :count)
.by(1)
note = project.notes.diff_notes.take
expect(note).to be_valid
expect(note.imported_from).to eq(::Import::SOURCE_GITHUB.to_s)
expect(note.noteable_type).to eq('MergeRequest')
expect(note.noteable_id).to eq(merge_request.id)
expect(note.project_id).to eq(project.id)

View File

@ -21,32 +21,45 @@ RSpec.describe Packages::Nuget::Symbol, type: :model, feature_category: :package
it { is_expected.to validate_presence_of(:signature) }
it { is_expected.to validate_presence_of(:object_storage_key) }
it { is_expected.to validate_presence_of(:size) }
it { is_expected.to validate_uniqueness_of(:signature).scoped_to(:file_path) }
it { is_expected.to validate_uniqueness_of(:object_storage_key).case_insensitive }
it { is_expected.to validate_uniqueness_of(:signature).scoped_to(:file_path, :package_id) }
context 'when package is nil' do
let(:new_symbol) { build(:nuget_symbol, signature: symbol.signature) }
before do
new_symbol.package = nil
new_symbol.validate
end
it 'does not validate uniqueness of signature' do
expect(new_symbol.errors.messages_for(:signature)).not_to include 'has already been taken'
end
end
end
describe 'delegations' do
it { is_expected.to delegate_method(:project_id).to(:package) }
it { is_expected.to delegate_method(:project).to(:package) }
it { is_expected.to delegate_method(:project_id).to(:package).allow_nil }
it { is_expected.to delegate_method(:project).to(:package).allow_nil }
end
describe 'scopes' do
describe '.stale' do
subject { described_class.stale }
describe '.orphan' do
subject { described_class.orphan }
let_it_be(:symbol) { create(:nuget_symbol) }
let_it_be(:stale_symbol) { create(:nuget_symbol, :stale) }
let_it_be(:orphan_symbol) { create(:nuget_symbol, :orphan) }
it { is_expected.to contain_exactly(stale_symbol) }
it { is_expected.to contain_exactly(orphan_symbol) }
end
describe '.pending_destruction' do
subject { described_class.pending_destruction }
let_it_be(:symbol) { create(:nuget_symbol, :stale, :processing) }
let_it_be(:stale_symbol) { create(:nuget_symbol, :stale) }
let_it_be(:symbol) { create(:nuget_symbol, :orphan, :processing) }
let_it_be(:orphan_symbol) { create(:nuget_symbol, :orphan) }
it { is_expected.to contain_exactly(stale_symbol) }
it { is_expected.to contain_exactly(orphan_symbol) }
end
describe '.with_signature' do
@ -122,6 +135,14 @@ RSpec.describe Packages::Nuget::Symbol, type: :model, feature_category: :package
end
it { is_expected.to eq(symbol) }
context 'when package_id is not present' do
before do
symbol.update_column(:package_id, nil)
end
it { is_expected.to be_nil }
end
end
end

View File

@ -74,7 +74,7 @@ RSpec.describe VirtualRegistries::Packages::Maven::CachedResponse, type: :model,
end
describe 'associations' do
it do
it 'belongs to an upstream' do
is_expected.to belong_to(:upstream)
.class_name('VirtualRegistries::Packages::Maven::Upstream')
.inverse_of(:cached_responses)
@ -180,16 +180,15 @@ RSpec.describe VirtualRegistries::Packages::Maven::CachedResponse, type: :model,
subject(:create_or_update) do
with_threads do
file = Tempfile.new('test.txt').tap { |f| f.write('test') }
described_class.create_or_update_by!(
upstream: upstream,
group_id: upstream.group_id,
relative_path: '/test',
updates: { file: file, size: size, file_sha1: 'test' }
)
ensure
file.close
file.unlink
Tempfile.create('test.txt') do |file|
file.write('test')
described_class.create_or_update_by!(
upstream: upstream,
group_id: upstream.group_id,
relative_path: '/test',
updates: { file: file, size: size, file_sha1: 'test' }
)
end
end
end
@ -275,26 +274,6 @@ RSpec.describe VirtualRegistries::Packages::Maven::CachedResponse, type: :model,
end
end
describe '#bump_statistics', :freeze_time do
let_it_be_with_reload(:cached_response) { create(:virtual_registries_packages_maven_cached_response) }
subject(:bump) { cached_response.bump_statistics }
it 'updates the correct statistics' do
expect { bump }.to change { cached_response.downloaded_at }.to(Time.zone.now)
end
context 'with include_upstream_checked_at' do
subject(:bump) { cached_response.bump_statistics(include_upstream_checked_at: true) }
it 'updates the correct statistics' do
expect { bump }
.to change { cached_response.reload.downloaded_at }.to(Time.zone.now)
.and change { cached_response.upstream_checked_at }.to(Time.zone.now)
end
end
end
context 'with loose foreign key on virtual_registries_packages_maven_cached_responses.upstream_id' do
it_behaves_like 'update by a loose foreign key' do
let_it_be(:parent) { create(:virtual_registries_packages_maven_upstream) }
@ -315,12 +294,12 @@ RSpec.describe VirtualRegistries::Packages::Maven::CachedResponse, type: :model,
# create a race condition - structure from https://blog.arkency.com/2015/09/testing-race-conditions/
wait_for_it = true
threads = Array.new(count) do |i|
threads = Array.new(count) do
Thread.new do
# A loop to make threads busy until we `join` them
true while wait_for_it
yield(i)
yield
end
end

View File

@ -1339,7 +1339,6 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, :aggregate_failures, fea
relative_path: "/#{path}",
upstream_etag: nil,
upstream_checked_at: Time.zone.now,
downloaded_at: Time.zone.now,
file_sha1: kind_of(String),
file_md5: kind_of(String)
)

View File

@ -194,6 +194,30 @@ RSpec.describe Import::ReassignPlaceholderUserRecordsService, feature_category:
)
end
it 'calls UserProjectAccessChangedService' do
expect_next_instance_of(UserProjectAccessChangedService, reassign_to_user.id) do |service|
expect(service).to receive(:execute)
end
service.execute
end
it 'does not call UserProjectAccessChangedService when there are no memberships created' do
Import::Placeholders::Membership.delete_all
expect(UserProjectAccessChangedService).not_to receive(:new)
expect { service.execute }.not_to change { Member.count }
end
it 'does not call UserProjectAccessChangedService when only group memberships are created' do
Import::Placeholders::Membership.where(project: project).delete_all
expect(UserProjectAccessChangedService).not_to receive(:new)
expect { service.execute }.to change { GroupMember.count }.by(1)
end
it 'deletes reassigned placeholder references and memberships for the source user' do
expect { service.execute }
.to change { Import::SourceUserPlaceholderReference.where(source_user: source_user).count }.to(0)
@ -203,6 +227,7 @@ RSpec.describe Import::ReassignPlaceholderUserRecordsService, feature_category:
context 'when reassigned by user no longer exists' do
before do
source_user.reassigned_by_user.destroy!
source_user.reload
end
it 'can still create memberships' do
@ -210,7 +235,8 @@ RSpec.describe Import::ReassignPlaceholderUserRecordsService, feature_category:
end
it 'logs a warning' do
expect(::Import::Framework::Logger).to receive(:warn).with(
allow(Import::Framework::Logger).to receive(:warn)
expect(Import::Framework::Logger).to receive(:warn).with(
hash_including(
message: 'Reassigned by user was not found, this may affect membership checks',
source_user_id: source_user.id

View File

@ -151,6 +151,14 @@ RSpec.describe Notes::CreateService, feature_category: :team_planning do
described_class.new(project, user, opts).execute
end
context 'when importing execute option is set to true' do
it 'does not enqueue NewNoteWorker' do
expect(NewNoteWorker).not_to receive(:perform_async)
described_class.new(project, user, opts).execute(importing: true)
end
end
context 'issue is an incident' do
let(:issue) { create(:incident, project: project) }

View File

@ -1162,12 +1162,6 @@ RSpec.describe QuickActions::InterpretService, feature_category: :text_editors d
it_behaves_like 'assign_reviewer command'
end
context 'with the "request_review" alias' do
let(:content) { "/request_review @#{developer.username}" }
it_behaves_like 'assign_reviewer command'
end
context 'with no user' do
let(:content) { '/assign_reviewer' }
@ -1183,6 +1177,91 @@ RSpec.describe QuickActions::InterpretService, feature_category: :text_editors d
end
end
describe 'request_review command' do
let(:content) { "/request_review @#{developer.username}" }
let(:issuable) { merge_request }
context 'with one user' do
it 'assigns a reviewer to a single user' do
_, updates, message = service.execute(content, issuable)
translated_string = _("Requested a review from %{developer_to_reference}.")
formatted_message = format(translated_string, developer_to_reference: developer.to_reference.to_s)
expect(updates).to eq(reviewer_ids: [developer.id])
expect(message).to eq(formatted_message)
end
it 'explains command' do
_, explanations = service.explain(content, issuable)
expect(explanations).to eq(["Requests a review from #{developer.to_reference}."])
end
end
context 'when user is already assigned' do
let(:merge_request) { create(:merge_request, source_project: project, reviewers: [developer]) }
it 'requests a review' do
expect_next_instance_of(::MergeRequests::RequestReviewService) do |service|
expect(service).to receive(:execute).with(merge_request, developer)
end
_, _, message = service.execute(content, issuable)
translated_string = _("Requested a review from %{developer_to_reference}.")
formatted_message = format(translated_string, developer_to_reference: developer.to_reference.to_s)
expect(message).to eq(formatted_message)
end
end
# CE does not have multiple reviewers
context 'assign command with multiple reviewers' do
before do
project.add_developer(developer2)
end
# There's no guarantee that the reference extractor will preserve
# the order of the mentioned users since this is dependent on the
# order in which rows are returned. We just ensure that at least
# one of the mentioned users is assigned.
context 'assigns to one of the two users' do
let(:content) { "/request_review @#{developer.username} @#{developer2.username}" }
it 'assigns to a single reviewer' do
_, updates, message = service.execute(content, issuable)
expect(updates[:reviewer_ids].count).to eq(1)
reviewer = updates[:reviewer_ids].first
expect([developer.id, developer2.id]).to include(reviewer)
user = reviewer == developer.id ? developer : developer2
expect(message).to match("Requested a review from #{user.to_reference}.")
end
end
end
context 'with "me" alias' do
let(:content) { '/request_review me' }
it 'assigns a reviewer to a single user' do
_, updates, message = service.execute(content, issuable)
translated_string = _("Requested a review from %{developer_to_reference}.")
formatted_message = format(translated_string, developer_to_reference: developer.to_reference.to_s)
expect(updates).to eq(reviewer_ids: [developer.id])
expect(message).to eq(formatted_message)
end
end
context 'with no user' do
let(:content) { '/request_review' }
it_behaves_like 'failed command', "Failed to request a review because no user was specified."
end
end
describe 'unassign_reviewer command' do
# CE does not have multiple reviewers, so basically anything
# after /unassign_reviewer (including whitespace) will remove

View File

@ -33,7 +33,6 @@ RSpec.describe VirtualRegistries::Packages::Maven::CachedResponses::CreateOrUpda
expect(last_cached_response).to have_attributes(
group_id: registry.group.id,
upstream_checked_at: Time.zone.now,
downloaded_at: Time.zone.now,
relative_path: "/#{path}",
upstream_etag: etag,
content_type: content_type,
@ -72,7 +71,6 @@ RSpec.describe VirtualRegistries::Packages::Maven::CachedResponses::CreateOrUpda
expect(execute.payload).to eq(cached_response: last_cached_response)
expect(last_cached_response).to have_attributes(
downloaded_at: Time.zone.now,
upstream_checked_at: Time.zone.now,
upstream_etag: etag
)

View File

@ -82,12 +82,6 @@ RSpec.describe VirtualRegistries::Packages::Maven::HandleFileRequestService, :ag
it_behaves_like 'returning a service response success response', action: :download_file
it 'bumps the statistics', :freeze_time do
stub_external_registry_request(etag: etag_returned_by_upstream)
expect { execute }.to change { cached_response.reload.downloaded_at }.to(Time.zone.now)
end
context 'and is too old' do
before do
cached_response.update!(upstream_checked_at: 1.year.ago)
@ -101,9 +95,7 @@ RSpec.describe VirtualRegistries::Packages::Maven::HandleFileRequestService, :ag
it 'bumps the statistics', :freeze_time do
stub_external_registry_request(etag: etag_returned_by_upstream)
expect { execute }
.to change { cached_response.reload.downloaded_at }.to(Time.zone.now)
.and change { cached_response.upstream_checked_at }.to(Time.zone.now)
expect { execute }.to change { cached_response.reload.upstream_checked_at }.to(Time.zone.now)
end
end

View File

@ -87,7 +87,7 @@ RSpec.describe Packages::CleanupPackageRegistryWorker, type: :worker, feature_ca
end
context 'with nuget symbols pending destruction' do
let_it_be(:nuget_symbol) { create(:nuget_symbol, :stale) }
let_it_be(:nuget_symbol) { create(:nuget_symbol, :orphan) }
it_behaves_like 'an idempotent worker' do
it 'queues the cleanup job' do

View File

@ -21,9 +21,9 @@ RSpec.describe Packages::Nuget::CleanupStaleSymbolsWorker, type: :worker, featur
context 'with work to do' do
let_it_be(:symbol_1) { create(:nuget_symbol) }
let_it_be(:symbol_2) { create(:nuget_symbol, :stale) }
let_it_be(:symbol_2) { create(:nuget_symbol, :orphan) }
it 'deletes the stale symbol', :aggregate_failures do
it 'deletes the orphan symbol', :aggregate_failures do
expect(worker).to receive(:log_extra_metadata_on_done).with(:nuget_symbol_id, symbol_2.id)
expect(Packages::Nuget::Symbol).to receive(:next_pending_destruction).with(order_by: nil).and_call_original
expect { perform_work }.to change { Packages::Nuget::Symbol.count }.by(-1)
@ -31,8 +31,8 @@ RSpec.describe Packages::Nuget::CleanupStaleSymbolsWorker, type: :worker, featur
end
end
context 'with a stale symbol' do
let_it_be(:symbol) { create(:nuget_symbol, :stale) }
context 'with an orphan symbol' do
let_it_be(:symbol) { create(:nuget_symbol, :orphan) }
context 'with an error during deletion' do
before do