Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-08-21 15:11:36 +00:00
parent 606d784b5b
commit ba7e516994
58 changed files with 914 additions and 312 deletions

View File

@ -1 +1 @@
c29c5ba968d141237000185734baa95e122db80b
1a16fa05c2645a0abba4e2f028e1fdbe5d85be2f

View File

@ -180,7 +180,6 @@ export default {
return {
'is-replying gl-pt-0!': this.isReplying,
'internal-note': this.isDiscussionInternal,
'public-note': !this.isDiscussionInternal,
'gl-pt-0!': !this.discussion.diff_discussion && this.isReplying,
};
},

View File

@ -1,5 +1,6 @@
import { padWithZeros } from '~/lib/utils/datetime/date_format_utility';
import { isValidDate, differenceInMinutes } from '~/lib/utils/datetime_utility';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import {
CUSTOM_DATE_RANGE_OPTION,
@ -193,3 +194,9 @@ export function isTracingDateRangeOutOfBounds({ value, startDate, endDate }) {
}
return false;
}
export function urlWithStringifiedPayloadParam(url, payload, paramName) {
return mergeUrlParams({ [paramName]: JSON.stringify(payload) }, url, {
spreadArrays: true,
});
}

View File

@ -43,7 +43,7 @@
background-color: $line-target-blue;
}
+ .public-note.discussion-reply-holder {
+ .discussion-reply-holder {
padding-top: $gl-padding-12 !important;
}

View File

@ -27,10 +27,20 @@ module Ci
record = find_by(build_id: build_id, partition_id: partition_id)
return record if record
upsert({ build_id: build_id, partition_id: partition_id }, unique_by: :build_id)
upsert({ build_id: build_id, partition_id: partition_id }, unique_by: unique_by_columns_for_upsert)
find_by!(build_id: build_id, partition_id: partition_id)
end
# Temporary fix to correctly identify an unique index for upsert
# should be replaced with `%w[build_id partition_id]` in %17.5
def self.unique_by_columns_for_upsert
unique_indexes = connection.schema_cache.indexes(table_name).select(&:unique)
columns = %w[partition_id build_id]
return columns if unique_indexes.any? { |index| index.columns == columns }
columns.reverse
end
# The job is retried around 5 times during the 7 days retention period for
# trace chunks as defined in `Ci::BuildTraceChunks::RedisBase::CHUNK_REDIS_TTL`
def can_attempt_archival_now?

View File

@ -18,7 +18,7 @@ module VirtualRegistries
prevent(*create_read_update_admin_destroy(:virtual_registry))
end
rule { can?(:read_group) }.policy do
rule { group.guest | admin | group.has_projects }.policy do
enable :read_virtual_registry
end

View File

@ -60,16 +60,13 @@ module WorkItems
def interpret_quick_actions!(work_item, widget_params, attributes = {})
return unless work_item.has_widget?(:description)
widget_description_param = widget_params[::WorkItems::Widgets::Description.api_symbol]
return unless widget_description_param
description_widget_params = widget_params[::WorkItems::Widgets::Description.api_symbol]
return unless description_widget_params
merge_quick_actions_into_params!(work_item, params: widget_description_param)
merge_quick_actions_into_params!(work_item, params: description_widget_params)
# cleanup `description` param so that it is not passed into common params after transform_quick_action_params
quick_action_params = widget_description_param.dup
quick_action_params.delete(:description)
parsed_params = work_item.transform_quick_action_params(quick_action_params)
# exclude `description` param so that it is not passed into common params after transform_quick_action_params
parsed_params = work_item.transform_quick_action_params(description_widget_params.except(:description))
widget_params.merge!(parsed_params[:widgets])
attributes.merge!(parsed_params[:common])

View File

@ -217,42 +217,24 @@ class IssuableBaseService < ::BaseContainerService
# If the description has not been edited, then just remove any quick actions
# in the current description.
def merge_quick_actions_into_params!(issuable, params:, only: nil)
interpret_params = quick_action_options
unedited_description = issuable.description
edited_description = params.fetch(:description, issuable.description)
target_description = params.fetch(:description, issuable.description)
target_text = issuable.new_record? || params[:description] ? edited_description : unedited_description
# only set the original_text if we're editing the issuable
original_text = params[:description] && !issuable.new_record? ? unedited_description : nil
sanitized_description, sanitized_command_params = interpret_quick_actions(target_text, issuable, params: interpret_params, only: only, original_text: original_text)
unless issuable.new_record? || params[:description]
edited_description = unedited_description
sanitized_command_params = nil
end
description, command_params = QuickActions::InterpretService.new(
container: container,
current_user: current_user,
params: quick_action_options
).execute_with_original_text(target_description, issuable, only: only, original_text: issuable.description_was)
# Avoid a description already set on an issuable to be overwritten by a nil
params[:description] = sanitized_description if sanitized_description && sanitized_description != edited_description
params[:description] = description if description && description != target_description
params.merge!(sanitized_command_params) if sanitized_command_params
params.merge!(command_params)
end
def quick_action_options
{}
end
def interpret_quick_actions(new_text, issuable, params:, only:, original_text: nil)
sanitized_new_text, new_command_params = QuickActions::InterpretService.new(
container: container,
current_user: current_user,
params: params
).execute_with_original_text(new_text, issuable, only: only, original_text: original_text)
[sanitized_new_text, new_command_params]
end
def create(issuable, skip_system_notes: false)
initialize_callbacks!(issuable)

View File

@ -212,6 +212,10 @@ dast_site_validations:
- table: projects
column: project_id
on_delete: async_delete
dast_sites:
- table: projects
column: project_id
on_delete: async_delete
deployment_clusters:
- table: clusters
column: cluster_id

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
class CreateCiFinishedPipelinesHourly < ClickHouse::Migration
def up
execute <<~SQL
CREATE TABLE IF NOT EXISTS ci_finished_pipelines_hourly
(
`path` String DEFAULT '0/',
`status` LowCardinality(String) DEFAULT '',
`source` LowCardinality(String) DEFAULT '',
`ref` String DEFAULT '',
`started_at_bucket` DateTime64(6, 'UTC') DEFAULT now64(),
count_pipelines AggregateFunction(count)
)
ENGINE = AggregatingMergeTree()
ORDER BY (started_at_bucket, path, status, source, ref)
SQL
end
def down
execute <<~SQL
DROP TABLE IF EXISTS ci_finished_pipelines_hourly
SQL
end
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
class CreateCiFinishedPipelinesHourlyMv < ClickHouse::Migration
def up
execute <<~SQL
CREATE MATERIALIZED VIEW IF NOT EXISTS ci_finished_pipelines_hourly_mv
TO ci_finished_pipelines_hourly
AS
SELECT
path,
status,
source,
ref,
toStartOfInterval(started_at, INTERVAL 1 hour) AS started_at_bucket,
countState() AS count_pipelines
FROM ci_finished_pipelines
GROUP BY path, status, source, ref, started_at_bucket
SQL
end
def down
execute <<~SQL
DROP VIEW ci_finished_pipelines_hourly_mv
SQL
end
end

View File

@ -7,7 +7,7 @@ feature_categories:
description: Site to run dast scan on
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36659
milestone: '13.2'
gitlab_schema: gitlab_main_cell
gitlab_schema: gitlab_sec
allow_cross_foreign_keys:
- gitlab_main_clusterwide
sharding_key:

View File

@ -0,0 +1,11 @@
---
table_name: p_ci_build_trace_metadata
classes:
- Ci::BuildTraceMetadata
feature_categories:
- continuous_integration
description: Routing table for ci_build_trace_metadata
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/162310
milestone: '14.2'
gitlab_schema: gitlab_ci
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/458479

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
class CreatePCiBuildTraceMetadata < Gitlab::Database::Migration[2.2]
milestone '17.4'
# rubocop:disable Migration/EnsureFactoryForTable -- No factory needed
def change
create_table(:p_ci_build_trace_metadata, primary_key: [:build_id, :partition_id],
options: 'PARTITION BY LIST (partition_id)', if_not_exists: true) do |t|
t.bigint :build_id, null: false
t.bigint :partition_id, null: false
t.bigint :trace_artifact_id
t.datetime_with_timezone :last_archival_attempt_at
t.datetime_with_timezone :archived_at
t.integer :archival_attempts, default: 0, null: false, limit: 2
t.binary :checksum
t.binary :remote_checksum
t.index :trace_artifact_id
end
end
# rubocop:enable Migration/EnsureFactoryForTable -- No factory needed
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class DropIdxVulnerabilityOccurrencesDedup < Gitlab::Database::Migration[2.2]
milestone '17.4'
disable_ddl_transaction!
TABLE = :vulnerability_occurrences
INDEX_NAME = 'index_vulnerability_occurrences_deduplication'
COLUMNS = %i[project_id report_type project_fingerprint]
def up
remove_concurrent_index TABLE, COLUMNS, name: INDEX_NAME
end
def down
add_concurrent_index TABLE, COLUMNS, name: INDEX_NAME
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class RemoveProjectsDastSitesProjectIdFk < Gitlab::Database::Migration[2.2]
milestone '17.4'
disable_ddl_transaction!
FOREIGN_KEY_NAME = "fk_rails_6febb6ea9c"
def up
with_lock_retries do
remove_foreign_key_if_exists(:dast_sites, :projects,
name: FOREIGN_KEY_NAME, reverse_lock_order: true)
end
end
def down
add_concurrent_foreign_key(:dast_sites, :projects,
name: FOREIGN_KEY_NAME, column: :project_id,
target_column: :id, on_delete: :cascade)
end
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
class FkCiBuildsCiBuildTraceMetadata < Gitlab::Database::Migration[2.2]
include Gitlab::Database::PartitioningMigrationHelpers
disable_ddl_transaction!
milestone '17.4'
def up
add_concurrent_partitioned_foreign_key(
:p_ci_build_trace_metadata, :p_ci_builds,
name: :fk_rails_aebc78111f_p,
column: [:partition_id, :build_id],
target_column: [:partition_id, :id],
on_update: :cascade,
on_delete: :cascade,
reverse_lock_order: true
)
end
def down
with_lock_retries do
remove_foreign_key_if_exists :p_ci_build_trace_metadata, :p_ci_builds,
name: :fk_rails_aebc78111f_p, reverse_lock_order: true
end
end
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
class FkCiJobsArtifactsCiBuildTraceMetadata < Gitlab::Database::Migration[2.2]
include Gitlab::Database::PartitioningMigrationHelpers
disable_ddl_transaction!
milestone '17.4'
def up
add_concurrent_partitioned_foreign_key(
:p_ci_build_trace_metadata, :p_ci_job_artifacts,
name: :fk_21d25cac1a_p,
column: [:partition_id, :trace_artifact_id],
target_column: [:partition_id, :id],
on_update: :cascade,
on_delete: :cascade,
reverse_lock_order: true
)
end
def down
with_lock_retries do
remove_foreign_key_if_exists :p_ci_build_trace_metadata, :p_ci_job_artifacts,
name: :fk_21d25cac1a_p, reverse_lock_order: true
end
end
end

View File

@ -0,0 +1,62 @@
# frozen_string_literal: true
class PartitionCiBuildTraceMetadata < Gitlab::Database::Migration[2.2]
milestone '17.4'
disable_ddl_transaction!
# rubocop:disable Migration/SchemaAdditionMethodsNoPost -- recreates the table in the same transaction
def up
with_lock_retries do
lock_tables(:p_ci_builds, :p_ci_job_artifacts, :ci_build_trace_metadata, mode: :access_exclusive)
drop_table(:ci_build_trace_metadata)
connection.execute(<<~SQL)
CREATE TABLE IF NOT EXISTS ci_build_trace_metadata
PARTITION OF p_ci_build_trace_metadata
FOR VALUES IN (100, 101, 102);
SQL
end
end
def down
drop_table(:ci_build_trace_metadata, if_exists: true)
create_table(:ci_build_trace_metadata, id: false, if_not_exists: true) do |t|
t.bigint :build_id, null: false, default: nil, primary_key: true
t.bigint :trace_artifact_id
t.integer :archival_attempts, default: 0, null: false, limit: 2
t.binary :checksum
t.binary :remote_checksum
t.datetime_with_timezone :last_archival_attempt_at
t.datetime_with_timezone :archived_at
t.bigint :partition_id, null: false
t.index [:trace_artifact_id, :partition_id],
name: :index_ci_build_trace_metadata_on_trace_artifact_id_partition_id
t.index [:partition_id, :build_id], unique: true,
name: :index_ci_build_trace_metadata_on_partition_id_build_id
end
add_concurrent_foreign_key(
:ci_build_trace_metadata, :p_ci_builds,
column: [:partition_id, :build_id],
target_column: [:partition_id, :id],
on_update: :cascade,
on_delete: :cascade,
reverse_lock_order: true,
name: :fk_rails_aebc78111f_p
)
add_concurrent_foreign_key(
:ci_build_trace_metadata, :p_ci_job_artifacts,
column: [:partition_id, :trace_artifact_id],
target_column: [:partition_id, :id],
on_update: :cascade,
on_delete: :cascade,
reverse_lock_order: true,
name: :fk_21d25cac1a_p
)
end
# rubocop:enable Migration/SchemaAdditionMethodsNoPost
end

View File

@ -0,0 +1 @@
519360df6518a135db8b7f543819bfa1984ec0fc3f12cbf3324e0f99602c2987

View File

@ -0,0 +1 @@
3711a08edad1fa122bfce2c5c1183e6514430c1ea3253c707dbdf7c84eebeee2

View File

@ -0,0 +1 @@
76ac52c3eeb536a7a0393bf52d0dfe10029d70927cd28697b7bb57969b3ec47b

View File

@ -0,0 +1 @@
24f8129c565f649626fb34a05075a3c43acb3336020add263d0595facd45fc25

View File

@ -0,0 +1 @@
c7e5dc7f7ca4dbbf62ae0d53eef6beba539ddd75a556a1b20e3f8612997c1204

View File

@ -0,0 +1 @@
bf7bd395aac7d28c0982682b5356383d0de4d7b868fa5690c79adc6da4b70022

View File

@ -7743,15 +7743,27 @@ CREATE SEQUENCE ci_build_trace_chunks_id_seq
ALTER SEQUENCE ci_build_trace_chunks_id_seq OWNED BY ci_build_trace_chunks.id;
CREATE TABLE ci_build_trace_metadata (
CREATE TABLE p_ci_build_trace_metadata (
build_id bigint NOT NULL,
partition_id bigint NOT NULL,
trace_artifact_id bigint,
archival_attempts smallint DEFAULT 0 NOT NULL,
checksum bytea,
remote_checksum bytea,
last_archival_attempt_at timestamp with time zone,
archived_at timestamp with time zone,
partition_id bigint NOT NULL
archival_attempts smallint DEFAULT 0 NOT NULL,
checksum bytea,
remote_checksum bytea
)
PARTITION BY LIST (partition_id);
CREATE TABLE ci_build_trace_metadata (
build_id bigint NOT NULL,
partition_id bigint NOT NULL,
trace_artifact_id bigint,
last_archival_attempt_at timestamp with time zone,
archived_at timestamp with time zone,
archival_attempts smallint DEFAULT 0 NOT NULL,
checksum bytea,
remote_checksum bytea
);
CREATE TABLE ci_builds (
@ -20970,6 +20982,8 @@ ALTER TABLE ONLY namespace_descendants ATTACH PARTITION gitlab_partitions_static
ALTER TABLE ONLY namespace_descendants ATTACH PARTITION gitlab_partitions_static.namespace_descendants_31 FOR VALUES WITH (modulus 32, remainder 31);
ALTER TABLE ONLY p_ci_build_trace_metadata ATTACH PARTITION ci_build_trace_metadata FOR VALUES IN ('100', '101', '102');
ALTER TABLE ONLY p_ci_builds ATTACH PARTITION ci_builds FOR VALUES IN ('100');
ALTER TABLE ONLY p_ci_builds_metadata ATTACH PARTITION ci_builds_metadata FOR VALUES IN ('100');
@ -23143,8 +23157,11 @@ ALTER TABLE ONLY ci_build_report_results
ALTER TABLE ONLY ci_build_trace_chunks
ADD CONSTRAINT ci_build_trace_chunks_pkey PRIMARY KEY (id);
ALTER TABLE ONLY p_ci_build_trace_metadata
ADD CONSTRAINT p_ci_build_trace_metadata_pkey PRIMARY KEY (build_id, partition_id);
ALTER TABLE ONLY ci_build_trace_metadata
ADD CONSTRAINT ci_build_trace_metadata_pkey PRIMARY KEY (build_id);
ADD CONSTRAINT ci_build_trace_metadata_pkey PRIMARY KEY (build_id, partition_id);
ALTER TABLE ONLY p_ci_builds_metadata
ADD CONSTRAINT p_ci_builds_metadata_pkey PRIMARY KEY (id, partition_id);
@ -26196,6 +26213,10 @@ CREATE INDEX ca_aggregations_last_full_run_at ON analytics_cycle_analytics_aggre
CREATE INDEX ca_aggregations_last_incremental_run_at ON analytics_cycle_analytics_aggregations USING btree (last_incremental_run_at NULLS FIRST) WHERE (enabled IS TRUE);
CREATE INDEX index_p_ci_build_trace_metadata_on_trace_artifact_id ON ONLY p_ci_build_trace_metadata USING btree (trace_artifact_id);
CREATE INDEX ci_build_trace_metadata_trace_artifact_id_idx ON ci_build_trace_metadata USING btree (trace_artifact_id);
CREATE INDEX p_ci_builds_status_created_at_project_id_idx ON ONLY p_ci_builds USING btree (status, created_at, project_id) WHERE ((type)::text = 'Ci::Build'::text);
CREATE INDEX ci_builds_gitlab_monitor_metrics ON ci_builds USING btree (status, created_at, project_id) WHERE ((type)::text = 'Ci::Build'::text);
@ -27022,10 +27043,6 @@ CREATE UNIQUE INDEX index_ci_build_trace_chunks_on_build_id_and_chunk_index ON c
CREATE INDEX index_ci_build_trace_chunks_on_partition_id_build_id ON ci_build_trace_chunks USING btree (partition_id, build_id);
CREATE UNIQUE INDEX index_ci_build_trace_metadata_on_partition_id_build_id ON ci_build_trace_metadata USING btree (partition_id, build_id);
CREATE INDEX index_ci_build_trace_metadata_on_trace_artifact_id_partition_id ON ci_build_trace_metadata USING btree (trace_artifact_id, partition_id);
CREATE INDEX p_ci_builds_metadata_build_id_idx ON ONLY p_ci_builds_metadata USING btree (build_id) WHERE (has_exposed_artifacts IS TRUE);
CREATE INDEX index_ci_builds_metadata_on_build_id_and_has_exposed_artifacts ON ci_builds_metadata USING btree (build_id) WHERE (has_exposed_artifacts IS TRUE);
@ -30380,8 +30397,6 @@ CREATE INDEX index_vulnerability_occurrence_pipelines_occurrence_id_and_id ON vu
CREATE INDEX index_vulnerability_occurrence_pipelines_on_pipeline_id ON vulnerability_occurrence_pipelines USING btree (pipeline_id);
CREATE INDEX index_vulnerability_occurrences_deduplication ON vulnerability_occurrences USING btree (project_id, report_type, project_fingerprint);
CREATE INDEX index_vulnerability_occurrences_for_override_uuids_logic ON vulnerability_occurrences USING btree (project_id, report_type, location_fingerprint);
CREATE INDEX index_vulnerability_occurrences_on_initial_pipeline_id ON vulnerability_occurrences USING btree (initial_pipeline_id);
@ -32254,6 +32269,10 @@ ALTER INDEX index_on_namespace_descendants_outdated ATTACH PARTITION gitlab_part
ALTER INDEX namespace_descendants_pkey ATTACH PARTITION gitlab_partitions_static.namespace_descendants_31_pkey;
ALTER INDEX p_ci_build_trace_metadata_pkey ATTACH PARTITION ci_build_trace_metadata_pkey;
ALTER INDEX index_p_ci_build_trace_metadata_on_trace_artifact_id ATTACH PARTITION ci_build_trace_metadata_trace_artifact_id_idx;
ALTER INDEX p_ci_builds_status_created_at_project_id_idx ATTACH PARTITION ci_builds_gitlab_monitor_metrics;
ALTER INDEX p_ci_builds_metadata_pkey ATTACH PARTITION ci_builds_metadata_pkey;
@ -32844,7 +32863,7 @@ ALTER TABLE ONLY coverage_fuzzing_corpuses
ALTER TABLE ONLY namespace_settings
ADD CONSTRAINT fk_20cf0eb2f9 FOREIGN KEY (default_compliance_framework_id) REFERENCES compliance_management_frameworks(id) ON DELETE SET NULL;
ALTER TABLE ONLY ci_build_trace_metadata
ALTER TABLE p_ci_build_trace_metadata
ADD CONSTRAINT fk_21d25cac1a_p FOREIGN KEY (partition_id, trace_artifact_id) REFERENCES p_ci_job_artifacts(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY users_star_projects
@ -35028,9 +35047,6 @@ ALTER TABLE ONLY project_compliance_framework_settings
ALTER TABLE ONLY users_security_dashboard_projects
ADD CONSTRAINT fk_rails_6f6cf8e66e FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE ONLY dast_sites
ADD CONSTRAINT fk_rails_6febb6ea9c FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY analytics_dashboards_pointers
ADD CONSTRAINT fk_rails_7027b7eaa9 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@ -35502,7 +35518,7 @@ ALTER TABLE ONLY analytics_cycle_analytics_group_stages
ALTER TABLE ONLY metrics_dashboard_annotations
ADD CONSTRAINT fk_rails_aeb11a7643 FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_build_trace_metadata
ALTER TABLE p_ci_build_trace_metadata
ADD CONSTRAINT fk_rails_aebc78111f_p FOREIGN KEY (partition_id, build_id) REFERENCES p_ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY bulk_import_trackers

View File

@ -669,8 +669,7 @@ WARNING:
[very specific cases](https://handbook.gitlab.com/handbook/engineering/workflow/#criteria-for-merging-during-broken-master).
For other cases, follow these [handbook instructions](https://handbook.gitlab.com/handbook/engineering/workflow/#merging-during-broken-master).
- If the latest pipeline was created before the merge request was approved, start a new pipeline to ensure that full RSpec suite has been run. You may skip this step only if the merge request does not contain any backend change.
- If the **latest [merged results pipeline](../ci/pipelines/merged_results_pipelines.md)** was **created less than 8 hours ago**, you
may merge without starting a new pipeline as the merge request is close enough to the target branch.
- If the **latest [merged results pipeline](../ci/pipelines/merged_results_pipelines.md)** was **created less than 8 hours ago (72 hours for stable branches)**, you may merge without starting a new pipeline as the merge request is close enough to the target branch.
- When you set the MR to auto-merge, you should take over
subsequent revisions for anything that would be spotted after that.
- For merge requests that have had [Squash and merge](../user/project/merge_requests/squash_and_merge.md) set,

View File

@ -246,7 +246,7 @@ Merge train pipelines run a single `pre-merge-checks` job which ensures the late
1. A [Merged Results pipeline](../../ci/pipelines/merged_results_pipelines.md)
1. A [`tier-3` pipeline](#pipeline-tiers) (i.e. full pipeline, not predictive one)
1. Created at most 8 hours ago
1. Created at most 8 hours ago (72 hours for stable branches)
We opened [a feedback issue](https://gitlab.com/gitlab-org/quality/engineering-productivity/team/-/issues/513)
to iterate on this solution.

View File

@ -102,3 +102,23 @@ The following table shows what type of aggregation is used for each search perio
### Data retention
GitLab has a retention limit of 30 days for all ingested metrics.
### Create an issue for a metric
You can create an issue to track any action taken to resolve or investigate a metric. To create an issue for a metric:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Metrics**.
1. From the list of metrics, select a metric.
1. Select **Create issue**.
The issue is created in the selected project and pre-filled with information from the metric.
You can edit the issue title and description.
### View issues related to a metric
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Metrics**.
1. From the list of metrics, select a metric.
1. Scroll to **Related issues**.
1. Optional. To view the issue details, select an issue.

View File

@ -277,7 +277,11 @@ A job is queued. When the job finishes, the subscription details are updated.
## View your subscription
If you are an administrator, you can view the status of your subscription:
Prerequisites:
- You must be an administrator.
You can view the status of your subscription:
1. On the left sidebar, at the bottom, select **Admin**.
1. Select **Subscription**.

View File

@ -17,7 +17,7 @@ platform for software development. GitLab adds many powerful
| | | |
|--|--|--|
| [**Get started**](get_started.md) **{chevron-right}** | [**Install Git**](how_to_install_git/index.md) **{chevron-right}** | [**Tutorial: Create your first commit**](../../tutorials/make_first_git_commit/index.md) **{chevron-right}** |
| [**Clone a repository to your local machine**](clone.md) **{chevron-right}** | [**Create a branch for your changes**](branch.md) **{chevron-right}** | [**Add files to your branch**](../../gitlab-basics/add-file.md) **{chevron-right}** |
| [**Stash changes for later**](stash.md) **{chevron-right}** | [**Undo changes**](undo.md) **{chevron-right}** | [**Tutorial: Update Git commit messages**](../../tutorials/update_commit_messages/index.md) **{chevron-right}** |
| [**Rebase to address merge conflicts**](git_rebase.md) **{chevron-right}** | [**Common Git commands**](../../gitlab-basics/start-using-git.md) **{chevron-right}** | [**Troubleshooting**](troubleshooting_git.md) **{chevron-right}** |
| [**Get started**](get_started.md) **{chevron-right}**<br><br>Overview of how features fit together. | [**Install Git**](how_to_install_git/index.md) **{chevron-right}**<br><br>Download, configuration, system requirements. | [**Tutorial: Create your first commit**](../../tutorials/make_first_git_commit/index.md) **{chevron-right}**<br><br>Initial commit, Git basics, repository setup. |
| [**Clone a repository to your local machine**](clone.md) **{chevron-right}**<br><br>Local repository, clone, remote repository, SSH. | [**Create a branch for your changes**](branch.md) **{chevron-right}**<br><br>Branching, branch switch, checkout. | [**Add files to your branch**](../../gitlab-basics/add-file.md) **{chevron-right}**<br><br>Git add, staging changes, file management, commits. |
| [**Stash changes for later**](stash.md) **{chevron-right}**<br><br>Temporary storage, work in progress, context switching. | [**Undo changes**](undo.md) **{chevron-right}**<br><br>Reverting commits, removing changes, Git reset, unstage. | [**Tutorial: Update Git commit messages**](../../tutorials/update_commit_messages/index.md) **{chevron-right}**<br><br>Commit message editing, version history, best practices. |
| [**Rebase to address merge conflicts**](git_rebase.md) **{chevron-right}**<br><br>Conflict resolution, rebase, branch management. | [**Common Git commands**](../../gitlab-basics/start-using-git.md) **{chevron-right}**<br><br>Git cheatsheet, basic operations, command line. | [**Troubleshooting**](troubleshooting_git.md) **{chevron-right}**<br><br>Error resolution, common issues, debugging, Git problems. |

View File

@ -336,10 +336,13 @@ return this error:
To resolve this issue, you can update the password expiration by either:
- Using the `gitlab-rails console`:
- Using the [GitLab Rails console](../../administration/operations/rails_console.md)
to check and update the user data:
```ruby
gitlab-rails console
user = User.find_by_username('<USERNAME>')
user.password_expired?
user.password_expires_at
user.update!(password_expires_at: nil)
```

View File

@ -11,5 +11,5 @@ Store your source files in a repository and create merge requests. Write, debug,
| | | |
|--|--|--|
| [**Getting started**](../user/get_started/get_started_managing_code.md) **{chevron-right}** | [**Repositories**](../user/project/repository/index.md) **{chevron-right}** | [**Merge requests**](../user/project/merge_requests/index.md) **{chevron-right}** |
| [**Remote development**](../user/project/remote_development/index.md) **{chevron-right}** | | |
| [**Getting started**](../user/get_started/get_started_managing_code.md) **{chevron-right}**<br><br>Overview of how features fit together. | [**Repositories**](../user/project/repository/index.md) **{chevron-right}**<br><br>Version control, code storage, Git repositories, repository monitoring. | [**Merge requests**](../user/project/merge_requests/index.md) **{chevron-right}**<br><br>Code review, collaboration, branch merging, commits. |
| [**Remote development**](../user/project/remote_development/index.md) **{chevron-right}**<br><br>Web IDE, workspaces. | | |

View File

@ -24,11 +24,11 @@ with [Scaled Agile Framework (SAFe)](https://handbook.gitlab.com/handbook/market
| | | |
|--|--|--|
| [**Getting started**](../user/get_started/get_started_planning_work.md) **{chevron-right}** | [**Tutorial: Use GitLab for scrum**](../tutorials/scrum_events/index.md) **{chevron-right}** | [**Tutorial: Use GitLab for Kanban**](../tutorials/kanban/index.md) **{chevron-right}** |
| [**Labels**](../user/project/labels.md) **{chevron-right}** | [**Iterations**](../user/group/iterations/index.md) **{chevron-right}** | [**Milestones**](../user/project/milestones/index.md) **{chevron-right}** |
| [**Issues**](../user/project/issues/index.md) **{chevron-right}** | [**Issue boards**](../user/project/issue_board.md) **{chevron-right}** | [**Comments and threads**](../user/discussions/index.md) **{chevron-right}** |
| [**Tasks**](../user/tasks.md) **{chevron-right}** | [**Requirements**](../user/project/requirements/index.md) **{chevron-right}** | [**Time tracking**](../user/project/time_tracking.md) **{chevron-right}** |
| [**CRM**](../user/crm/index.md) **{chevron-right}** | [**Wikis**](../user/project/wiki/index.md) **{chevron-right}** | [**Epics**](../user/group/epics/index.md) **{chevron-right}** |
| [**Roadmaps**](../user/group/roadmap/index.md) **{chevron-right}** | [**Planning hierarchies**](../user/group/planning_hierarchy/index.md) **{chevron-right}** | [**Objectives and key results**](../user/okrs.md) **{chevron-right}** |
| [**Keyboard shortcuts**](../user/shortcuts.md) **{chevron-right}** | [**Quick actions**](../user/project/quick_actions.md) **{chevron-right}** | [**Markdown**](../user/markdown.md) **{chevron-right}** |
| [**To-Do List**](../user/todos.md) **{chevron-right}** | | |
| [**Getting started**](../user/get_started/get_started_planning_work.md) **{chevron-right}** <br><br>Overview of how features fit together. | [**Tutorial: Use GitLab for scrum**](../tutorials/scrum_events/index.md) **{chevron-right}** <br><br>Sprints, backlog, user stories, scrum lifecycle. | [**Tutorial: Use GitLab for Kanban**](../tutorials/kanban/index.md) **{chevron-right}** <br><br>Kanban board, columns, work in progress, flow, distribution. |
| [**Labels**](../user/project/labels.md) **{chevron-right}** <br><br>Project labels, group labels, nested scopes, filtering. | [**Iterations**](../user/group/iterations/index.md) **{chevron-right}** <br><br>Time-boxed workflow, program increments, cadence, sprints. | [**Milestones**](../user/project/milestones/index.md) **{chevron-right}** <br><br>Burndown charts, goals, progress tracking, releases. |
| [**Issues**](../user/project/issues/index.md) **{chevron-right}** <br><br>Tasks, bug reports, feature requests, tracking. | [**Issue boards**](../user/project/issue_board.md) **{chevron-right}** <br><br>Visualization, workflow, Kanban, prioritization. | [**Comments and threads**](../user/discussions/index.md) **{chevron-right}** <br><br> Mentions, locked discussions, internal notes, thread resolution. |
| [**Tasks**](../user/tasks.md) **{chevron-right}** <br><br>Task labels, confidential tasks, linked items, task weights. | [**Requirements**](../user/project/requirements/index.md) **{chevron-right}** <br><br>Acceptance criteria, requirements test reports, CSV import. | [**Time tracking**](../user/project/time_tracking.md) **{chevron-right}** <br><br>Estimates, time spent, reporting. |
| [**CRM**](../user/crm/index.md) **{chevron-right}** <br><br>Customer management, organizations, contacts, permissions. | [**Wikis**](../user/project/wiki/index.md) **{chevron-right}** <br><br>Documentation, external wikis, wiki events, history. | [**Epics**](../user/group/epics/index.md) **{chevron-right}** <br><br>Roadmaps, hierarchies, planning, issue progress. |
| [**Roadmaps**](../user/group/roadmap/index.md) **{chevron-right}** <br><br>Epic progress, timelines, milestones, goals. | [**Planning hierarchies**](../user/group/planning_hierarchy/index.md) **{chevron-right}** <br><br>Organization, structure, multi-level epics, nesting. | [**Objectives and key results**](../user/okrs.md) **{chevron-right}** <br><br>Goal setting, performance tracking, child objectives, health status. |
| [**Keyboard shortcuts**](../user/shortcuts.md) **{chevron-right}** <br><br>Global shortcuts, navigation, quick access. | [**Quick actions**](../user/project/quick_actions.md) **{chevron-right}** <br><br>Commands, shortcuts, inline actions. | [**Markdown**](../user/markdown.md) **{chevron-right}** <br><br>Formatting, inline HTML, GitLab-specific references, diagrams and flowcharts. |
| [**To-Do List**](../user/todos.md) **{chevron-right}** <br><br>Task management, actions, access changes. | | |

View File

@ -12,7 +12,7 @@ and give everyone access to the projects they need.
| | | |
|--|--|--|
| [**Tutorial: Set up your organization**](../tutorials/manage_user/index.md) **{chevron-right}** | [**Namespaces**](../user/namespace/index.md) **{chevron-right}** | [**Members**](../user/project/members/index.md) **{chevron-right}** |
| [**Organization** (in development)](../user/organization/index.md) **{chevron-right}** | [**Groups**](../user/group/index.md) **{chevron-right}** | [**Sharing projects and groups**](../user/project/members/sharing_projects_groups.md) **{chevron-right}** |
| [**Compliance**](../administration/compliance.md) **{chevron-right}** | [**Enterprise users**](../user/enterprise_user/index.md) **{chevron-right}** | [**Service accounts**](../user/profile/service_accounts.md) **{chevron-right}** |
| [**User account options**](../user/profile/index.md) **{chevron-right}** | [**SSH keys**](../user/ssh.md) **{chevron-right}** | [**GitLab.com settings**](../user/gitlab_com/index.md) **{chevron-right}** |
| [**Tutorial: Set up your organization**](../tutorials/manage_user/index.md) **{chevron-right}**<br><br>Setup, configuration, onboarding, organization structure. | [**Namespaces**](../user/namespace/index.md) **{chevron-right}**<br><br>Organization, hierarchy, project grouping. | [**Members**](../user/project/members/index.md) **{chevron-right}**<br><br>User management, roles, permissions, access levels. |
| [**Organization** (in development)](../user/organization/index.md) **{chevron-right}**<br><br>Namespace hierarchy. | [**Groups**](../user/group/index.md) **{chevron-right}**<br><br>Project management, access control, client groups, team groups. | [**Sharing projects and groups**](../user/project/members/sharing_projects_groups.md) **{chevron-right}**<br><br>Invitations, group inheritance, project visibility. |
| [**Compliance**](../administration/compliance.md) **{chevron-right}**<br><br>Compliance center, audit events, security policies, compliance frameworks. | [**Enterprise users**](../user/enterprise_user/index.md) **{chevron-right}**<br><br>Domain verification, two-factor authentication, enterprise user management, SAML response. | [**Service accounts**](../user/profile/service_accounts.md) **{chevron-right}**<br><br>Machine user, rate limits, personal access tokens. |
| [**User account options**](../user/profile/index.md) **{chevron-right}**<br><br>Profile settings, preferences, authentication, notifications. | [**SSH keys**](../user/ssh.md) **{chevron-right}**<br><br>Authentication, permissions, key types, ownership. | [**GitLab.com settings**](../user/gitlab_com/index.md) **{chevron-right}**<br><br>Instance configurations. |

View File

@ -61,7 +61,7 @@ DETAILS:
- Helps you understand the selected code by explaining it more clearly.
- LLM: Anthropic [Claude 3.5 Sonnet](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet)
- View documentation for explaining code in:
- [The IDE](../gitlab_duo_chat/examples.md#explain-code).
- [The IDE](../gitlab_duo_chat/examples.md#explain-selected-code).
- [A file](../../user/project/repository/code_explain.md).
- [A merge request](../../user/project/merge_requests/changes.md#explain-code-in-a-merge-request).

View File

@ -34,10 +34,46 @@ its knowledge base is updated daily.
- On GitLab.com the, the most recent version of the documentation is used.
- On Self-managed and GitLab Dedicated, the documentation for the version of the instance is used.
## Ask about code
## Explain selected code
DETAILS:
**Tier GitLab.com and Self-managed:** Premium or Ultimate for a limited time. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Tier: GitLab.com and Self-managed:** Premium or Ultimate for a limited time. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Editors:** GitLab UI, Web IDE, VS Code, JetBrains IDEs
**LLMs:** Anthropic: [`claude-3-5-sonnet-20240620`](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet)
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429915) for GitLab.com in GitLab 16.7.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429915) for self-managed and GitLab Dedicated in GitLab 16.8.
You can ask GitLab Duo Chat to explain selected code:
1. Select some code in your IDE.
1. In Duo Chat, type `/explain`.
![Selecting code and asking GitLab Duo Chat to explain using the /explain slash command.](img/code_selection_duo_chat.png)
You can also add additional instructions to be considered, for example:
- `/explain the performance`
- `/explain focus on the algorithm`
- `/explain the performance gains or losses using this code`
- `/explain the object inheritance` (classes, object-oriented)
- `/explain why a static variable is used here` (C++)
- `/explain how this function would cause a segmentation fault` (C)
- `/explain how concurrency works in this context` (Go)
- `/explain how the request reaches the client` (REST API, database)
For more information, see [Use GitLab Duo Chat in VS Code](index.md#use-gitlab-duo-chat-in-vs-code).
In the GitLab UI, you can also explain code in:
- A [file](../project/repository/code_explain.md).
- A [merge request](../project/merge_requests/changes.md#explain-code-in-a-merge-request).
## Ask about or generate code
DETAILS:
**Tier: GitLab.com and Self-managed:** Premium or Ultimate for a limited time. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Editors:** GitLab UI, Web IDE, VS Code, JetBrains IDEs
**LLMs:** Anthropic: [`claude-3-5-sonnet-20240620`](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet)
@ -45,7 +81,15 @@ DETAILS:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122235) for GitLab.com in GitLab 16.1.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122235) for self-managed and GitLab Dedicated in GitLab 16.8.
You can also ask GitLab Duo Chat to generate code:
You can ask GitLab Duo Chat questions about code by pasting that code into
the Duo Chat window. For example:
```plaintext
Provide a clear explanation of this Ruby code: def sum(a, b) a + b end.
Describe what this code does and how it works.
```
You can also ask Chat to generate code. For example:
- `Write a Ruby function that prints 'Hello, World!' when called.`
- `Develop a JavaScript program that simulates a two-player Tic-Tac-Toe game. Provide both game logic and user interface, if applicable.`
@ -54,11 +98,45 @@ You can also ask GitLab Duo Chat to generate code:
- `Create a product-consumer example with threads and shared memory in C++. Use atomic locks when possible.`
- `Generate Rust code for high performance gRPC calls. Provide a source code example for a server and client.`
And you can ask GitLab Duo Chat to explain code:
## Refactor code in the IDE
- `Provide a clear explanation of the given Ruby code: def sum(a, b) a + b end. Describe what this code does and how it works.`
DETAILS:
**Tier: GitLab.com and Self-managed:** Premium or Ultimate for a limited time. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Editors:** Web IDE, VS Code, JetBrains IDEs
**LLMs:** Anthropic: [`claude-3-5-sonnet-20240620`](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet)
Alternatively, you can use the [`/explain` command](examples.md#explain-code) to explain the selected code in your editor.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429915) for GitLab.com in GitLab 16.7.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429915) for self-managed and GitLab Dedicated in GitLab 16.8.
`/refactor` is a special command to generate a refactoring suggestion for the selected code in your editor.
You can include additional instructions to be considered. For example:
- Use a specific coding pattern, for example `/refactor with ActiveRecord` or `/refactor into a class providing static functions`.
- Use a specific library, for example `/refactor using mysql`.
- Use a specific function/algorithm, for example `/refactor into a stringstream with multiple lines` in C++.
- Refactor to a different programming language, for example `/refactor to TypeScript`.
- Focus on performance, for example `/refactor improving performance`.
- Focus on potential vulnerabilities, for example `/refactor avoiding memory leaks and exploits`.
## Fix code in the IDE
DETAILS:
**Tier: GitLab.com and Self-managed:** Premium or Ultimate for a limited time. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Editors:** Web IDE, VS Code, JetBrains IDEs
**LLMs:** Anthropic: [`claude-3-5-sonnet-20240620`](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet)
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429915) for GitLab.com, self-managed and GitLab Dedicated in GitLab 17.3.
`/fix` is a special command to generate a fix suggestion for the selected code in your editor.
You can include additional instructions to be considered. For example:
- Focus on grammar and typos, for example, `/fix grammar mistakes and typos`.
- Focus on a concrete algorithm or problem description, for example, `/fix duplicate database inserts` or `/fix race conditions`.
- Focus on potential bugs that are not directly visible, for example, `/fix potential bugs`.
- Focus on code performance problems, for example, `/fix performance problems`.
- Focus on fixing the build when the code does not compile, for example, `/fix the build`.
## Ask about CI/CD
@ -128,74 +206,6 @@ DETAILS:
[Learn more](../application_security/vulnerabilities/index.md#explaining-a-vulnerability).
## Explain code
DETAILS:
**Tier: GitLab.com and Self-managed:** Premium or Ultimate for a limited time. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Editors:** GitLab UI, Web IDE, VS Code, JetBrains IDEs
**LLMs:** Anthropic: [`claude-3-5-sonnet-20240620`](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet)
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429915) for GitLab.com in GitLab 16.7.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429915) for self-managed and GitLab Dedicated in GitLab 16.8.
`/explain` is a special command to explain the selected code in your editor.
You can also add additional instructions to be considered, for example: `/explain the performance`
See [Use GitLab Duo Chat in VS Code](index.md#use-gitlab-duo-chat-in-vs-code) for more information.
- `/explain focus on the algorithm`
- `/explain the performance gains or losses using this code`
- `/explain the object inheritance` (classes, object-oriented)
- `/explain why a static variable is used here` (C++)
- `/explain how this function would cause a segmentation fault` (C)
- `/explain how concurrency works in this context` (Go)
- `/explain how the request reaches the client` (REST API, database)
You can also use the Web UI to explain code in:
- A [file](../project/repository/code_explain.md).
- A [merge request](../project/merge_requests/changes.md#explain-code-in-a-merge-request).
## Refactor code in the IDE
DETAILS:
**Tier: GitLab.com and Self-managed:** Premium or Ultimate for a limited time. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Editors:** Web IDE, VS Code, JetBrains IDEs
**LLMs:** Anthropic: [`claude-3-5-sonnet-20240620`](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet)
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429915) for GitLab.com in GitLab 16.7.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429915) for self-managed and GitLab Dedicated in GitLab 16.8.
`/refactor` is a special command to generate a refactoring suggestion for the selected code in your editor.
You can include additional instructions to be considered. For example:
- Use a specific coding pattern, for example `/refactor with ActiveRecord` or `/refactor into a class providing static functions`.
- Use a specific library, for example `/refactor using mysql`.
- Use a specific function/algorithm, for example `/refactor into a stringstream with multiple lines` in C++.
- Refactor to a different programming language, for example `/refactor to TypeScript`.
- Focus on performance, for example `/refactor improving performance`.
- Focus on potential vulnerabilities, for example `/refactor avoiding memory leaks and exploits`.
## Fix code in the IDE
DETAILS:
**Tier: GitLab.com and Self-managed:** Premium or Ultimate for a limited time. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Editors:** Web IDE, VS Code, JetBrains IDEs
**LLMs:** Anthropic: [`claude-3-5-sonnet-20240620`](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet)
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429915) for GitLab.com, self-managed and GitLab Dedicated in GitLab 17.3.
`/fix` is a special command to generate a fix suggestion for the selected code in your editor.
You can include additional instructions to be considered. For example:
- Focus on grammar and typos, for example, `/fix grammar mistakes and typos`.
- Focus on a concrete algorithm or problem description, for example, `/fix duplicate database inserts` or `/fix race conditions`.
- Focus on potential bugs that are not directly visible, for example, `/fix potential bugs`.
- Focus on code performance problems, for example, `/fix performance problems`.
- Focus on fixing the build when the code does not compile, for example, `/fix the build`.
## Write tests in the IDE
DETAILS:
@ -307,8 +317,8 @@ Use the following commands to quickly accomplish specific tasks.
| /clear | [Delete all conversations permanently and clear the chat window](#delete-or-reset-the-conversation) |
| /reset | [Start a new conversation, but keep the previous conversations visible in the chat window](#delete-or-reset-the-conversation) |
| /tests | [Write tests](#write-tests-in-the-ide) |
| /explain | [Explain code](../gitlab_duo_chat/examples.md#explain-code) |
| /vulnerability_explain | [Explain current vulnerability](../gitlab_duo/index.md#vulnerability-explanation) |
| /refactor | [Refactor the code](../gitlab_duo_chat/examples.md#refactor-code-in-the-ide) |
| /explain | [Explain code](#explain-selected-code) |
| /vulnerability_explain | [Explain current vulnerability](../application_security/vulnerabilities/index.md#explaining-a-vulnerability) |
| /refactor | [Refactor the code](#refactor-code-in-the-ide) |
| /troubleshoot | [Troubleshoot failed CI/CD jobs with root cause analysis](#troubleshoot-failed-cicd-jobs-with-root-cause-analysis) |
| /fix | [Fix the code](../gitlab_duo_chat/examples.md#fix-code-in-the-ide) |
| /fix | [Fix the code](#fix-code-in-the-ide) |

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -82,7 +82,7 @@ For more information about slash commands, refer to the documentation:
- [/tests](../gitlab_duo_chat/examples.md#write-tests-in-the-ide)
- [/refactor](../gitlab_duo_chat/examples.md#refactor-code-in-the-ide)
- [/fix](../gitlab_duo_chat/examples.md#fix-code-in-the-ide)
- [/explain](../gitlab_duo_chat/examples.md#explain-code)
- [/explain](../gitlab_duo_chat/examples.md#explain-selected-code)
## `Error M4001`

View File

@ -261,7 +261,7 @@ We cannot guarantee that the large language model produces results that are corr
You can also explain code in:
- A [file](../../../user/project/repository/code_explain.md).
- The [IDE](../../../user/gitlab_duo_chat/examples.md#explain-code).
- The [IDE](../../../user/gitlab_duo_chat/examples.md#explain-selected-code).
## Expand or collapse comments

View File

@ -17,10 +17,10 @@ GitLab does not limit the number of private projects you can create.
| | | |
|--|--|--|
| [**Getting started**](../../user/get_started/get_started_projects.md) **{chevron-right}** | [**Create a project**](index.md) **{chevron-right}** | [**Manage projects**](working_with_projects.md) **{chevron-right}** |
| [**Project visibility**](../public_access.md) **{chevron-right}** | [**Project settings**](working_with_projects.md) **{chevron-right}** | [**Description templates**](../../user/project/description_templates.md) **{chevron-right}** |
| [**Project access tokens**](../project/settings/project_access_tokens.md) **{chevron-right}** | [**Deploy keys**](../../user/project/deploy_keys/index.md) **{chevron-right}** | [**Deploy tokens**](../../user/project/deploy_tokens/index.md) **{chevron-right}** |
| [**Share projects**](../project/members/share_project_with_groups.md) **{chevron-right}** | [**Reserved project and group names**](../../user/reserved_names.md) **{chevron-right}** | [**Search**](../../user/search/index.md) **{chevron-right}** |
| [**Badges**](../../user/project/badges.md) **{chevron-right}** | [**Project topics**](../../user/project/project_topics.md) **{chevron-right}** | [**Code intelligence**](../../user/project/code_intelligence.md) **{chevron-right}** |
| [**Import and migrate**](../../user/project/import/index.md) **{chevron-right}** | [**System notes**](../../user/project/system_notes.md) **{chevron-right}** | [**Transfer a project to another namespace**](../../user/project/import/index.md) **{chevron-right}** |
| [**Use a project as a Go package**](../../user/project/use_project_as_go_package.md) **{chevron-right}** | [**Tutorial: Build a protected workflow for your project**](../../tutorials/protected_workflow/index.md) **{chevron-right}** | [**Troubleshooting**](../../user/project/troubleshooting.md) **{chevron-right}** |
| [**Getting started**](../../user/get_started/get_started_projects.md) **{chevron-right}**<br><br>Overview of how features fit together. | [**Create a project**](index.md) **{chevron-right}**<br><br>New project, project templates. | [**Manage projects**](working_with_projects.md) **{chevron-right}**<br><br>Settings, configuration, project activity, project deletion. |
| [**Project visibility**](../public_access.md) **{chevron-right}****<br><br>Public, private, internal. | [**Project settings**](working_with_projects.md) **{chevron-right}**<br><br>Project features, analytics, project permissions. | [**Description templates**](../../user/project/description_templates.md) **{chevron-right}**<br><br>Issue templates, merge request templates, instance and group templates. |
| [**Project access tokens**](../project/settings/project_access_tokens.md) **{chevron-right}**<br><br>Authentication, create, revoke, token expiration. | [**Deploy keys**](../../user/project/deploy_keys/index.md) **{chevron-right}**<br><br>Public SSH keys, repository access, bot users, read-only access. | [**Deploy tokens**](../../user/project/deploy_tokens/index.md) **{chevron-right}**<br><br>Repository cloning, token creation, container registry. |
| [**Share projects**](../project/members/share_project_with_groups.md)**{chevron-right}**<br><br>Member roles, invitations, group access. | [**Reserved project and group names**](../../user/reserved_names.md) **{chevron-right}**<br><br>Naming conventions, restrictions, reserved names. | [**Search**](../../user/search/index.md) **{chevron-right}**<br><br>Basic, advanced, exact, search scope, commit SHA search. |
| [**Badges**](../../user/project/badges.md) **{chevron-right}**<br><br>Pipeline status, group, project, custom badges. | [**Project topics**](../../user/project/project_topics.md) **{chevron-right}**<br><br>Project organization, subscribe, view. | [**Code intelligence**](../../user/project/code_intelligence.md) **{chevron-right}**<br><br>Type signatures, symbol documentation, go-to definition. |
| [**Import and migrate**](../../user/project/import/index.md) **{chevron-right}**<br><br>Repository migration, third-party repositories, user contribution mapping. | [**System notes**](../../user/project/system_notes.md) **{chevron-right}**<br><br>Event history, activity log, comments history. | [**Transfer a project to another namespace**](../../user/project/import/index.md) **{chevron-right}**<br><br>Namespace transfer, subscription transfer. |
| [**Use a project as a Go package**](../../user/project/use_project_as_go_package.md) **{chevron-right}**<br><br>Go modules, import calls. | [**Tutorial: Build a protected workflow for your project**](../../tutorials/protected_workflow/index.md) **{chevron-right}**<br><br>Security, approval rules, branch protection. | [**Troubleshooting**](../../user/project/troubleshooting.md) **{chevron-right}**<br><br>Problem solving, common issues, debugging, error resolution. |

View File

@ -42,4 +42,4 @@ We cannot guarantee that the large language model produces results that are corr
You can also explain code in:
- A [merge request](../../../user/project/merge_requests/changes.md#explain-code-in-a-merge-request).
- The [IDE](../../../user/gitlab_duo_chat/examples.md#explain-code).
- The [IDE](../../../user/gitlab_duo_chat/examples.md#explain-selected-code).

View File

@ -199,6 +199,13 @@ e.send(:design_repo_saver).send(:save)
# The following line should show you the export_path similar to /var/opt/gitlab/gitlab-rails/shared/tmp/gitlab_exports/@hashed/49/94/4994....
s = Gitlab::ImportExport::Saver.new(exportable: p, shared: p.import_export_shared, user: u)
# Prior to GitLab 17.0, the `user` parameter was not supported. If you encounter an
# error with the above or are unsure whether or not to supply the `user`
# argument, use the following check:
Gitlab::ImportExport::Saver.instance_method(:initialize).parameters.include?([:keyreq, :user])
# If the preceding check returns false, omit the user argument:
s = Gitlab::ImportExport::Saver.new(exportable: p, shared: p.import_export_shared)
# To try and upload use:
s.send(:compress_and_save)
s.send(:save_upload)

View File

@ -32,6 +32,10 @@ module ClickHouse
self.class.new(@query_builder.offset(count))
end
def group(...)
self.class.new(@query_builder.group(...))
end
def select(...)
self.class.new(@query_builder.select(...))
end

View File

@ -0,0 +1,41 @@
# frozen_string_literal: true
module ClickHouse # rubocop:disable Gitlab/BoundedContexts -- Existing module
module Models
module Ci
class FinishedPipelinesHourly < ClickHouse::Models::BaseModel
def self.table_name
'ci_finished_pipelines_hourly'
end
def self.for_project(project)
new.for_project(project)
end
def self.by_status(statuses)
new.by_status(statuses)
end
def self.group_by_status
new.group_by_status
end
def for_project(project)
where(path: project.project_namespace.traversal_path)
end
def by_status(statuses)
where(status: statuses)
end
def group_by_status
group([@query_builder.table[:status]])
end
def count_pipelines_function
Arel::Nodes::NamedFunction.new('countMerge', [@query_builder.table[:count_pipelines]])
end
end
end
end
end

View File

@ -90,6 +90,14 @@ module ClickHouse
new_instance
end
def group(*columns)
new_instance = deep_clone
new_instance.manager.group(*columns)
new_instance
end
def limit(count)
manager.take(count)
self

View File

@ -14,12 +14,14 @@ end
require 'time'
class PreMergeChecks
DEFAULT_API_ENDPOINT = "https://gitlab.com/api/v4"
MERGE_TRAIN_REF_REGEX = %r{\Arefs/merge-requests/\d+/train\z}
TIER_IDENTIFIER_REGEX = /tier:\d/
REQUIRED_TIER_IDENTIFIER = 'tier:3'
PREDICTIVE_PIPELINE_IDENTIFIER = 'predictive'
PIPELINE_FRESHNESS_THRESHOLD_IN_HOURS = 8
DEFAULT_API_ENDPOINT = "https://gitlab.com/api/v4"
MERGE_TRAIN_REF_REGEX = %r{\Arefs/merge-requests/\d+/train\z}
PIPELINE_FRESHNESS_DEFAULT_THRESHOLD_IN_HOURS = 8
PIPELINE_FRESHNESS_STABLE_BRANCHES_THRESHOLD_IN_HOURS = 72
PREDICTIVE_PIPELINE_IDENTIFIER = 'predictive'
REQUIRED_TIER_IDENTIFIER = 'tier:3'
STABLE_BRANCH_SUFFIX = '-stable-ee'
TIER_IDENTIFIER_REGEX = /tier:\d/
PreMergeChecksFailedError = Class.new(StandardError)
PreMergeChecksStatus = Struct.new(:exitstatus, :message) do
@ -31,10 +33,12 @@ class PreMergeChecks
def initialize(
api_endpoint: ENV.fetch('CI_API_V4_URL', DEFAULT_API_ENDPOINT),
project_id: ENV['CI_PROJECT_ID'],
merge_request_iid: ENV['CI_MERGE_REQUEST_IID'])
merge_request_iid: ENV['CI_MERGE_REQUEST_IID'],
target_branch: ENV['CI_MERGE_REQUEST_TARGET_BRANCH_NAME'])
@api_endpoint = api_endpoint
@project_id = project_id
@merge_request_iid = merge_request_iid.to_i
@target_branch = target_branch
end
def execute
@ -62,7 +66,7 @@ class PreMergeChecks
private
attr_reader :api_endpoint, :project_id, :merge_request_iid
attr_reader :api_endpoint, :project_id, :merge_request_iid, :target_branch
def api_client
@api_client ||= begin
@ -77,6 +81,7 @@ class PreMergeChecks
def check_required_ids!
fail_check!("Missing project_id!") unless project_id
fail_check!("Missing merge_request_iid!") if merge_request_iid == 0
fail_check!("Missing target_branch!") unless target_branch
end
def check_pipeline_for_merged_results!(pipeline)
@ -101,10 +106,17 @@ class PreMergeChecks
def check_pipeline_freshness!(pipeline)
hours_ago = ((Time.now - Time.parse(pipeline.created_at)) / 3600).ceil(2)
return if hours_ago < PIPELINE_FRESHNESS_THRESHOLD_IN_HOURS
threshold =
if target_branch_is_stable_branch?
PIPELINE_FRESHNESS_STABLE_BRANCHES_THRESHOLD_IN_HOURS
else
PIPELINE_FRESHNESS_DEFAULT_THRESHOLD_IN_HOURS
end
return if hours_ago < threshold
fail_check! <<~TEXT
Expected latest pipeline (#{pipeline.web_url}) to be created within the last #{PIPELINE_FRESHNESS_THRESHOLD_IN_HOURS} hours (it was created #{hours_ago} hours ago)!
Expected latest pipeline (#{pipeline.web_url}) to be created within the last #{threshold} hours (it was created #{hours_ago} hours ago)!
Please start a new pipeline.
TEXT
@ -126,6 +138,10 @@ class PreMergeChecks
end
end
def target_branch_is_stable_branch?
target_branch.end_with?(STABLE_BRANCH_SUFFIX)
end
def fail_check!(text)
raise PreMergeChecksFailedError, text
end
@ -144,12 +160,18 @@ if $PROGRAM_NAME == __FILE__
options[:merge_request_iid] = value
end
opts.on("-t", "--target-branch [string]", String, "Target branch name") do |value|
options[:target_branch] = value
end
opts.on("-h", "--help") do
puts "Usage: #{File.basename(__FILE__)} [--project_id <PROJECT_ID>] [--merge_request_iid <MERGE_REQUEST_IID>]"
puts "Usage: #{File.basename(__FILE__)} [--project_id <PROJECT_ID>] " \
"[--merge_request_iid <MERGE_REQUEST_IID>] [--target-branch <TARGET_BRANCH>]"
puts
puts "Examples:"
puts
puts "#{File.basename(__FILE__)} --project_id \"gitlab-org/gitlab\" --merge_request_iid \"1\""
puts "#{File.basename(__FILE__)} --project_id \"gitlab-org/gitlab\" " \
"--merge_request_iid \"1\" --target-branch \"master\""
exit
end

View File

@ -10,31 +10,33 @@ RSpec.describe 'Database schema', feature_category: :database do
let(:columns_name_with_jsonb) { retrieve_columns_name_with_jsonb }
IGNORED_INDEXES_ON_FKS = {
ai_testing_terms_acceptances: %w[user_id], # testing terms only have 1 entry, and if the user is deleted the record should remain
application_settings: %w[instance_administration_project_id instance_administrators_group_id],
ci_build_trace_metadata: [%w[partition_id build_id], %w[partition_id trace_artifact_id]], # the index on build_id is enough
ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[upstream_pipeline_partition_id upstream_pipeline_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081
ci_daily_build_group_report_results: [%w[partition_id last_pipeline_id]], # index on last_pipeline_id is sufficient
ci_pipeline_artifacts: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipeline_chat_data: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipeline_messages: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipeline_metadata: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipeline_variables: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipelines: [%w[auto_canceled_by_partition_id auto_canceled_by_id]], # index on auto_canceled_by_id is sufficient
ci_pipelines_config: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_sources_pipelines: [%w[source_partition_id source_pipeline_id], %w[partition_id pipeline_id]],
ci_sources_projects: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient
notes: %w[namespace_id], # this index is added in an async manner, hence it needs to be ignored in the first phase.
p_ci_build_trace_metadata: [%w[partition_id build_id], %w[partition_id trace_artifact_id]], # the index on build_id is enough
p_ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[upstream_pipeline_partition_id upstream_pipeline_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081
p_ci_builds_execution_configs: [%w[partition_id pipeline_id]], # the index on pipeline_id is enough
p_ci_pipeline_variables: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
p_ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient
# `search_index_id index_type` is the composite foreign key configured for `search_namespace_index_assignments`,
# but in Search::NamespaceIndexAssignment model, only `search_index_id` is used as foreign key and indexed
search_namespace_index_assignments: [%w[search_index_id index_type]],
slack_integrations_scopes: [%w[slack_api_scope_id]],
notes: %w[namespace_id], # this index is added in an async manner, hence it needs to be ignored in the first phase.
users: [%w[accepted_term_id]],
ci_pipeline_artifacts: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_sources_projects: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_daily_build_group_report_results: [%w[partition_id last_pipeline_id]], # index on last_pipeline_id is sufficient
ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[upstream_pipeline_partition_id upstream_pipeline_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081
ci_pipeline_variables: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
p_ci_pipeline_variables: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipelines: [%w[auto_canceled_by_partition_id auto_canceled_by_id]], # index on auto_canceled_by_id is sufficient
ci_pipelines_config: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipeline_metadata: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
ci_pipeline_messages: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
p_ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[upstream_pipeline_partition_id upstream_pipeline_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081
ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient
p_ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient
ai_testing_terms_acceptances: %w[user_id], # testing terms only have 1 entry, and if the user is deleted the record should remain
p_ci_builds_execution_configs: [%w[partition_id pipeline_id]], # the index on pipeline_id is enough
ci_sources_pipelines: [%w[source_partition_id source_pipeline_id], %w[partition_id pipeline_id]],
snippets: %w[organization_id] # this index is added in an async manner, hence it needs to be ignored in the first phase.
snippets: %w[organization_id], # this index is added in an async manner, hence it needs to be ignored in the first phase.
users: [%w[accepted_term_id]]
}.with_indifferent_access.freeze
# If splitting FK and table removal into two MRs as suggested in the docs, use this constant in the initial FK removal MR.

View File

@ -207,23 +207,6 @@ describe('noteable_discussion component', () => {
expect(replyWrapper.exists()).toBe(true);
expect(replyWrapper.classes('internal-note')).toBe(true);
});
it('should add `public-note` class when the discussion is not internal', async () => {
const softCopyInternalNotes = [...discussionMock.notes];
const mockPublicNotes = softCopyInternalNotes.splice(0, 2);
mockPublicNotes[0].internal = false;
const mockDiscussion = {
...discussionMock,
notes: [...mockPublicNotes],
};
wrapper.setProps({ discussion: mockDiscussion });
await nextTick();
const replyWrapper = wrapper.find('[data-testid="reply-wrapper"]');
expect(replyWrapper.exists()).toBe(true);
expect(replyWrapper.classes('public-note')).toBe(true);
});
});
describe('for resolved thread', () => {

View File

@ -7,6 +7,7 @@ import {
formattedTimeFromDate,
isTracingDateRangeOutOfBounds,
validatedDateRangeQuery,
urlWithStringifiedPayloadParam,
} from '~/observability/utils';
import {
CUSTOM_DATE_RANGE_OPTION,
@ -271,3 +272,15 @@ describe('validatedDateRangeQuery', () => {
expect(result).toEqual({ value: '1h' });
});
});
describe('urlWithStringifiedPayloadParam', () => {
it('returns the url with a stringified param', () => {
expect(
urlWithStringifiedPayloadParam(
'http://gdk.test:3443/?foo=bar',
{ a: 'b', c: 'd' },
'my_param',
),
).toBe('http://gdk.test:3443/?foo=bar&my_param=%7B%22a%22%3A%22b%22%2C%22c%22%3A%22d%22%7D');
});
});

View File

@ -90,6 +90,19 @@ RSpec.describe ClickHouse::Models::BaseModel, feature_category: :database do
end
end
describe '#group' do
it 'returns a new instance with grouped results' do
dummy_instance = dummy_class.new(query_builder)
expect(query_builder).to receive(:group).with(:id, :name).and_return(updated_query_builder)
new_instance = dummy_instance.group(:id, :name)
expect(new_instance).to be_a(dummy_class)
expect(new_instance).not_to eq(dummy_instance)
end
end
describe '#select' do
it 'returns a new instance with selected fields' do
dummy_instance = dummy_class.new(query_builder)

View File

@ -0,0 +1,111 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ClickHouse::Models::Ci::FinishedPipelinesHourly, feature_category: :fleet_visibility do
let(:instance) { described_class.new }
let_it_be(:group) { create(:group, :nested) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:path) { project.reload.project_namespace.traversal_path }
specify { expect(path).to match(%r{\A(\d+/){3}\z}) }
describe '#for_project' do
it 'builds the correct SQL' do
expected_sql = <<~SQL.lines(chomp: true).join(' ')
SELECT * FROM "ci_finished_pipelines_hourly"
WHERE "ci_finished_pipelines_hourly"."path" = '#{path}'
SQL
result_sql = instance.for_project(project).to_sql
expect(result_sql.strip).to eq(expected_sql.strip)
end
end
describe '#by_status' do
it 'builds the correct SQL' do
expected_sql = <<~SQL.lines(chomp: true).join(' ')
SELECT * FROM "ci_finished_pipelines_hourly"
WHERE "ci_finished_pipelines_hourly"."status" IN ('failed', 'success')
SQL
result_sql = instance.by_status(%i[failed success]).to_sql
expect(result_sql.strip).to eq(expected_sql.strip)
end
end
describe '#group_by_status' do
it 'builds the correct SQL' do
expected_sql = <<~SQL.lines(chomp: true).join(' ')
SELECT "ci_finished_pipelines_hourly"."status"
FROM "ci_finished_pipelines_hourly"
GROUP BY "ci_finished_pipelines_hourly"."status"
SQL
result_sql = instance.select(:status).group_by_status.to_sql
expect(result_sql.strip).to eq(expected_sql.strip)
end
end
describe '#count_pipelines_function' do
it 'builds the correct SQL' do
expected_sql = <<~SQL.lines(chomp: true).join(' ')
SELECT "ci_finished_pipelines_hourly"."status", countMerge("ci_finished_pipelines_hourly"."count_pipelines")
FROM "ci_finished_pipelines_hourly"
SQL
result_sql = instance.select(:status, instance.count_pipelines_function).to_sql
expect(result_sql.strip).to eq(expected_sql.strip)
end
end
describe 'class methods' do
before do
allow(described_class).to receive(:new).and_return(instance)
end
describe '.for_project' do
it 'calls the corresponding instance method' do
expect(instance).to receive(:for_project).with(project)
described_class.for_project(project)
end
end
describe '.by_status' do
it 'calls the corresponding instance method' do
expect(instance).to receive(:by_status).with(:success)
described_class.by_status(:success)
end
end
describe '.group_by_status' do
it 'calls the corresponding instance method' do
expect(instance).to receive(:group_by_status)
described_class.group_by_status
end
end
end
describe 'method chaining' do
it 'builds the correct SQL with chained methods' do
expected_sql = <<~SQL.lines(chomp: true).join(' ')
SELECT "ci_finished_pipelines_hourly"."status" FROM "ci_finished_pipelines_hourly"
WHERE "ci_finished_pipelines_hourly"."path" = '#{path}'
AND "ci_finished_pipelines_hourly"."status" IN ('failed', 'success')
GROUP BY "ci_finished_pipelines_hourly"."status"
SQL
result_sql = instance.for_project(project).select(:status).by_status(%i[failed success]).group_by_status.to_sql
expect(result_sql.strip).to eq(expected_sql.strip)
end
end
end

View File

@ -278,6 +278,30 @@ RSpec.describe ClickHouse::QueryBuilder, feature_category: :database do
end
end
describe '#group' do
it 'builds correct group query' do
expected_sql = <<~SQL.lines(chomp: true).join(' ')
SELECT * FROM "test_table"
GROUP BY column1
SQL
sql = builder.group(:column1).to_sql
expect(sql).to eq(expected_sql)
end
it 'chains multiple groups when called multiple times' do
expected_sql = <<~SQL.lines(chomp: true).join(' ')
SELECT * FROM "test_table"
GROUP BY column1, column2
SQL
sql = builder.group(:column1).group(:column2).to_sql
expect(sql).to eq(expected_sql)
end
end
describe '#to_sql' do
it 'delegates to the Arel::SelectManager' do
expect(builder.send(:manager)).to receive(:to_sql)

View File

@ -46,7 +46,11 @@ RSpec.describe Gitlab::Database::PostgresPartition, type: :model, feature_catego
end
describe '.with_list_constraint' do
subject(:with_list_constraint) { described_class.with_list_constraint(partition_id) }
subject(:with_list_constraint) do
described_class
.with_parent_tables(Ci::Partitionable.registered_models.map(&:table_name))
.with_list_constraint(partition_id)
end
context 'when condition matches' do
let(:partition_id) { '102' }

View File

@ -13,29 +13,32 @@ RSpec.describe VirtualRegistries::Packages::Policies::GroupPolicy, feature_categ
describe 'read_virtual_registry' do
where(:group_visibility, :current_user, :allowed?) do
'PUBLIC' | nil | false
'PUBLIC' | ref(:non_group_member) | true
'PUBLIC' | ref(:guest) | true
'PUBLIC' | ref(:reporter) | true
'PUBLIC' | ref(:developer) | true
'PUBLIC' | ref(:maintainer) | true
'PUBLIC' | ref(:owner) | true
'PUBLIC' | nil | false
'PUBLIC' | ref(:non_group_member) | false
'PUBLIC' | ref(:guest) | true
'PUBLIC' | ref(:reporter) | true
'PUBLIC' | ref(:developer) | true
'PUBLIC' | ref(:maintainer) | true
'PUBLIC' | ref(:owner) | true
'PUBLIC' | ref(:organization_owner) | true
'INTERNAL' | nil | false
'INTERNAL' | ref(:non_group_member) | true
'INTERNAL' | ref(:guest) | true
'INTERNAL' | ref(:reporter) | true
'INTERNAL' | ref(:developer) | true
'INTERNAL' | ref(:maintainer) | true
'INTERNAL' | ref(:owner) | true
'INTERNAL' | nil | false
'INTERNAL' | ref(:non_group_member) | false
'INTERNAL' | ref(:guest) | true
'INTERNAL' | ref(:reporter) | true
'INTERNAL' | ref(:developer) | true
'INTERNAL' | ref(:maintainer) | true
'INTERNAL' | ref(:owner) | true
'INTERNAL' | ref(:organization_owner) | true
'PRIVATE' | nil | false
'PRIVATE' | ref(:non_group_member) | false
'PRIVATE' | ref(:guest) | true
'PRIVATE' | ref(:reporter) | true
'PRIVATE' | ref(:developer) | true
'PRIVATE' | ref(:maintainer) | true
'PRIVATE' | ref(:owner) | true
'PRIVATE' | nil | false
'PRIVATE' | ref(:non_group_member) | false
'PRIVATE' | ref(:guest) | true
'PRIVATE' | ref(:reporter) | true
'PRIVATE' | ref(:developer) | true
'PRIVATE' | ref(:maintainer) | true
'PRIVATE' | ref(:owner) | true
'PRIVATE' | ref(:organization_owner) | true
end
with_them do
@ -46,14 +49,42 @@ RSpec.describe VirtualRegistries::Packages::Policies::GroupPolicy, feature_categ
it { is_expected.to public_send(allowed? ? :be_allowed : :be_disallowed, :read_virtual_registry) }
end
context 'for deploy token' do
let(:deploy_token) do
create(:deploy_token, :group).tap do |token|
create(:group_deploy_token, group: target, deploy_token: token)
context 'with project membership' do
let_it_be(:project) { create(:project, group: group) }
let(:current_user) { non_group_member }
%i[
guest
reporter
developer
maintainer
owner
].each do |role|
context "for #{role}" do
before do
project.send(:"add_#{role}", current_user)
end
it { expect_allowed(:read_virtual_registry) }
end
end
end
subject { described_class.new(deploy_token, policy_subject) }
context 'for admin' do
let(:current_user) { admin }
context 'when admin mode is enabled', :enable_admin_mode do
it { expect_allowed(:read_virtual_registry) }
end
context 'when admin mode is disabled' do
it { expect_disallowed(:read_virtual_registry) }
end
end
context 'for deploy token' do
let(:deploy_token) { create(:deploy_token, :group, groups: [target]) }
let(:current_user) { deploy_token }
where(:target, :group_visibility, :read_virtual_registry, :allowed?) do
ref(:group) | 'PUBLIC' | true | true
@ -85,29 +116,32 @@ RSpec.describe VirtualRegistries::Packages::Policies::GroupPolicy, feature_categ
%i[create update destroy].each do |action|
describe "#{action}_virtual_registry" do
where(:group_visibility, :current_user, :allowed?) do
'PUBLIC' | nil | false
'PUBLIC' | ref(:non_group_member) | false
'PUBLIC' | ref(:guest) | false
'PUBLIC' | ref(:reporter) | false
'PUBLIC' | ref(:developer) | false
'PUBLIC' | ref(:maintainer) | true
'PUBLIC' | ref(:owner) | true
'PUBLIC' | nil | false
'PUBLIC' | ref(:non_group_member) | false
'PUBLIC' | ref(:guest) | false
'PUBLIC' | ref(:reporter) | false
'PUBLIC' | ref(:developer) | false
'PUBLIC' | ref(:maintainer) | true
'PUBLIC' | ref(:owner) | true
'PUBLIC' | ref(:organization_owner) | true
'INTERNAL' | nil | false
'INTERNAL' | ref(:non_group_member) | false
'INTERNAL' | ref(:guest) | false
'INTERNAL' | ref(:reporter) | false
'INTERNAL' | ref(:developer) | false
'INTERNAL' | ref(:maintainer) | true
'INTERNAL' | ref(:owner) | true
'INTERNAL' | nil | false
'INTERNAL' | ref(:non_group_member) | false
'INTERNAL' | ref(:guest) | false
'INTERNAL' | ref(:reporter) | false
'INTERNAL' | ref(:developer) | false
'INTERNAL' | ref(:maintainer) | true
'INTERNAL' | ref(:owner) | true
'INTERNAL' | ref(:organization_owner) | true
'PRIVATE' | nil | false
'PRIVATE' | ref(:non_group_member) | false
'PRIVATE' | ref(:guest) | false
'PRIVATE' | ref(:reporter) | false
'PRIVATE' | ref(:developer) | false
'PRIVATE' | ref(:maintainer) | true
'PRIVATE' | ref(:owner) | true
'PRIVATE' | nil | false
'PRIVATE' | ref(:non_group_member) | false
'PRIVATE' | ref(:guest) | false
'PRIVATE' | ref(:reporter) | false
'PRIVATE' | ref(:developer) | false
'PRIVATE' | ref(:maintainer) | true
'PRIVATE' | ref(:owner) | true
'PRIVATE' | ref(:organization_owner) | true
end
with_them do
@ -118,5 +152,17 @@ RSpec.describe VirtualRegistries::Packages::Policies::GroupPolicy, feature_categ
it { is_expected.to public_send(allowed? ? :be_allowed : :be_disallowed, :"#{action}_virtual_registry") }
end
end
context 'for admin' do
let(:current_user) { admin }
context 'when admin mode is enabled', :enable_admin_mode do
it { expect_allowed(:"#{action}_virtual_registry") }
end
context 'when admin mode is disabled' do
it { expect_disallowed(:"#{action}_virtual_registry") }
end
end
end
end

View File

@ -7,18 +7,18 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
include WorkhorseHelpers
include HttpBasicAuthHelpers
let_it_be_with_reload(:registry) { create(:virtual_registries_packages_maven_registry) }
let_it_be(:group) { create(:group) }
let_it_be_with_reload(:registry) { create(:virtual_registries_packages_maven_registry, group: group) }
let_it_be(:upstream) { create(:virtual_registries_packages_maven_upstream, registry: registry) }
let_it_be(:group) { registry.group }
let_it_be(:project) { create(:project, namespace: group) }
let_it_be(:user) { project.creator }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:user) { create(:user, owner_of: project) }
let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
let_it_be(:deploy_token) do
create(:deploy_token, :group, groups: [group], read_virtual_registry: true)
end
let_it_be(:headers) { user_basic_auth_header(user, personal_access_token) }
let(:personal_access_token) { create(:personal_access_token, user: user) }
let(:headers) { user_basic_auth_header(user, personal_access_token) }
shared_examples 'disabled feature flag' do
before do
@ -95,11 +95,11 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
end
context 'with a non member user' do
let_it_be(:user) { build_stubbed(:user) }
let_it_be(:user) { create(:user) }
where(:group_access_level, :status) do
'PUBLIC' | :ok
'INTERNAL' | :ok
'PUBLIC' | :forbidden
'INTERNAL' | :forbidden
'PRIVATE' | :not_found
end
@ -108,11 +108,7 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
end
if params[:status] == :ok
it_behaves_like 'successful response'
else
it_behaves_like 'returning response status', params[:status]
end
it_behaves_like 'returning response status', params[:status]
end
end
@ -323,11 +319,11 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
end
context 'with a non member user' do
let_it_be(:user) { build_stubbed(:user) }
let_it_be(:user) { create(:user) }
where(:group_access_level, :status) do
'PUBLIC' | :ok
'INTERNAL' | :ok
'PUBLIC' | :forbidden
'INTERNAL' | :forbidden
'PRIVATE' | :forbidden
end
with_them do
@ -335,11 +331,7 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
end
if params[:status] == :ok
it_behaves_like 'successful response'
else
it_behaves_like 'returning response status', params[:status]
end
it_behaves_like 'returning response status', params[:status]
end
end
@ -588,8 +580,8 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
let_it_be(:user) { create(:user) }
where(:group_access_level, :status) do
'PUBLIC' | :ok
'INTERNAL' | :ok
'PUBLIC' | :forbidden
'INTERNAL' | :forbidden
'PRIVATE' | :forbidden
end
@ -598,11 +590,7 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
end
if params[:status] == :ok
it_behaves_like 'successful response'
else
it_behaves_like 'returning response status', params[:status]
end
it_behaves_like 'returning response status', params[:status]
end
end
@ -782,11 +770,11 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
end
context 'with a non member user' do
let_it_be(:user) { build_stubbed(:user) }
let_it_be(:user) { create(:user) }
where(:group_access_level, :status) do
'PUBLIC' | :ok
'INTERNAL' | :ok
'PUBLIC' | :forbidden
'INTERNAL' | :forbidden
'PRIVATE' | :forbidden
end
@ -795,11 +783,7 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
end
if params[:status] == :ok
it_behaves_like 'successful response'
else
it_behaves_like 'returning response status', params[:status]
end
it_behaves_like 'returning response status', params[:status]
end
end

View File

@ -8,16 +8,17 @@ require_relative '../../../scripts/pipeline/pre_merge_checks'
RSpec.describe PreMergeChecks, time_travel_to: Time.parse('2024-05-29T10:00:00 UTC'), feature_category: :tooling do
include StubENV
let(:instance) { described_class.new }
let(:project_id) { '42' }
let(:merge_request_iid) { '1' }
let(:mr_pipelines_url) { "https://gitlab.test/api/v4/projects/#{project_id}/merge_requests/#{merge_request_iid}/pipelines" }
let(:instance) { described_class.new }
let(:project_id) { '42' }
let(:merge_request_iid) { '1' }
let(:target_branch) { 'master' }
let(:mr_pipelines_url) { "https://gitlab.test/api/v4/projects/#{project_id}/merge_requests/#{merge_request_iid}/pipelines" }
let(:latest_mr_pipeline_ref) { "refs/merge-requests/1/merge" }
let(:latest_mr_pipeline_status) { "success" }
let(:latest_mr_pipeline_ref) { "refs/merge-requests/1/merge" }
let(:latest_mr_pipeline_status) { "success" }
let(:latest_mr_pipeline_created_at) { "2024-05-29T07:15:00 UTC" }
let(:latest_mr_pipeline_web_url) { "https://gitlab.com/gitlab-org/gitlab/-/pipelines/1310472835" }
let(:latest_mr_pipeline_name) { "Ruby 3.2 MR [tier:3, gdk]" }
let(:latest_mr_pipeline_web_url) { "https://gitlab.com/gitlab-org/gitlab/-/pipelines/1310472835" }
let(:latest_mr_pipeline_name) { "Ruby 3.2 MR [tier:3, gdk]" }
let(:latest_mr_pipeline_short) do
{
id: 1309901620,
@ -78,7 +79,8 @@ RSpec.describe PreMergeChecks, time_travel_to: Time.parse('2024-05-29T10:00:00 U
stub_env(
'CI_API_V4_URL' => 'https://gitlab.test/api/v4',
'CI_PROJECT_ID' => project_id,
'CI_MERGE_REQUEST_IID' => merge_request_iid
'CI_MERGE_REQUEST_IID' => merge_request_iid,
'CI_MERGE_REQUEST_TARGET_BRANCH_NAME' => target_branch
)
end
@ -102,6 +104,16 @@ RSpec.describe PreMergeChecks, time_travel_to: Time.parse('2024-05-29T10:00:00 U
expect(instance.execute.message).to include("Missing merge_request_iid")
end
end
context 'when target_branch is missing' do
let(:target_branch) { nil }
it 'returns a failed PreMergeChecksStatus' do
expect(instance.execute).to be_a(described_class::PreMergeChecksStatus)
expect(instance.execute).not_to be_success
expect(instance.execute.message).to include("Missing target_branch")
end
end
end
describe '#execute' do
@ -138,6 +150,33 @@ RSpec.describe PreMergeChecks, time_travel_to: Time.parse('2024-05-29T10:00:00 U
allow(api_client).to receive(:pipeline).with(project_id, mr_pipelines[2][:id]).and_return(latest_mr_pipeline)
end
context 'and the target branch is a stable branch' do
let(:target_branch) { 'a-stable-branch-stable-ee' }
context 'and the latest pipeline is not fresh enough' do
let(:latest_mr_pipeline_created_at) { "2024-05-26T09:30:00 UTC" }
it 'returns a failed PreMergeChecksStatus' do
expect(instance.execute).to be_a(described_class::PreMergeChecksStatus)
expect(instance.execute).not_to be_success
expect(instance.execute.message)
.to include(
"Expected latest pipeline (#{latest_mr_pipeline_web_url}) to be created within the last 72 hours " \
"(it was created 72.5 hours ago)!"
)
end
end
context 'and the latest pipeline is fresh enough' do
let(:latest_mr_pipeline_created_at) { "2024-05-26T10:30:00 UTC" }
it 'returns a successful PreMergeChecksStatus' do
expect(instance.execute).to be_a(described_class::PreMergeChecksStatus)
expect(instance.execute).to be_success
end
end
end
context 'and it passes all the checks' do
it 'returns a successful PreMergeChecksStatus' do
expect(instance.execute).to be_a(described_class::PreMergeChecksStatus)

View File

@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe VirtualRegistries::Packages::Maven::HandleFileRequestService, :aggregate_failures, feature_category: :virtual_registry do
let_it_be(:registry) { create(:virtual_registries_packages_maven_registry, :with_upstream) }
let_it_be(:project) { create(:project, namespace: registry.group) }
let_it_be(:user) { create(:user, owner_of: project) }
let(:user) { project.creator }
let(:upstream) { registry.upstream }
let(:path) { 'com/test/package/1.2.3/package-1.2.3.pom' }
let(:upstream_resource_url) { upstream.url_for(path) }