Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-07-15 12:22:43 +00:00
parent 7131c1e219
commit 4abd579c45
121 changed files with 901 additions and 862 deletions

View File

@ -3736,11 +3736,6 @@ Gitlab/BoundedContexts:
- 'ee/app/workers/ldap_sync_worker.rb'
- 'ee/app/workers/licenses/reset_submit_license_usage_data_banner_worker.rb'
- 'ee/app/workers/llm/completion_worker.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/cleanup_previous_versions_records_worker.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/create_db_embeddings_per_doc_file_worker.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/create_embeddings_records_worker.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/embeddings_worker_context.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/set_embeddings_on_the_record_worker.rb'
- 'ee/app/workers/llm/namespace_access_cache_reset_worker.rb'
- 'ee/app/workers/llm/vertex_ai_access_token_refresh_worker.rb'
- 'ee/app/workers/members_destroyer/clean_up_group_protected_branch_rules_worker.rb'

View File

@ -139,10 +139,6 @@ Gitlab/FeatureFlagWithoutActor:
- 'ee/app/views/projects/settings/merge_requests/_merge_trains_settings.html.haml'
- 'ee/app/workers/elastic/migration_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/add_on_purchases/schedule_bulk_refresh_user_assignments_worker.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/cleanup_previous_versions_records_worker.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/create_db_embeddings_per_doc_file_worker.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/create_embeddings_records_worker.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/set_embeddings_on_the_record_worker.rb'
- 'ee/app/workers/llm/vertex_ai_access_token_refresh_worker.rb'
- 'ee/app/workers/search/index_curation_worker.rb'
- 'ee/app/workers/search/zoekt/scheduling_worker.rb'

View File

@ -1570,8 +1570,6 @@ Style/InlineDisableAnnotation:
- 'ee/app/workers/ldap_group_sync_worker.rb'
- 'ee/app/workers/ldap_sync_worker.rb'
- 'ee/app/workers/licenses/reset_submit_license_usage_data_banner_worker.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/cleanup_previous_versions_records_worker.rb'
- 'ee/app/workers/llm/embedding/gitlab_documentation/create_db_embeddings_per_doc_file_worker.rb'
- 'ee/app/workers/members_destroyer/clean_up_group_protected_branch_rules_worker.rb'
- 'ee/app/workers/merge_request_reset_approvals_worker.rb'
- 'ee/app/workers/new_epic_worker.rb'

View File

@ -1 +1 @@
412263801bb4a37fdf09aed95269342369dc74a7
47c3c8bc2d5a93e83eee6b250a06e4c39d9c929c

View File

@ -1 +1 @@
v17.2.0-rc1
v17.2.0-rc2

View File

@ -164,7 +164,7 @@ export default {
return referencePath.slice(0, referencePath.indexOf('#'));
},
showWorkItemEpics() {
return this.glFeatures.displayWorkItemEpicIssueSidebar;
return this.glFeatures.workItemEpics;
},
showEpicSidebarDropdownWidget() {
return this.epicFeatureAvailable && !this.isIncidentSidebar && this.activeBoardIssuable.id;

View File

@ -99,7 +99,7 @@ export default {
errorTexts: {
[LOAD_FAILURE]: __('We are currently unable to fetch data for this graph.'),
[PARSE_FAILURE]: __('There was an error parsing the data for this graph.'),
[UNSUPPORTED_DATA]: __('DAG visualization requires at least 3 dependent jobs.'),
[UNSUPPORTED_DATA]: __('Needs visualization requires at least 3 dependent jobs.'),
[DEFAULT]: __('An unknown error occurred while loading this graph.'),
},
emptyStateTexts: {
@ -108,9 +108,9 @@ export default {
'Using the %{codeStart}needs%{codeEnd} keyword makes jobs run before their stage is reached. Jobs run as soon as their %{codeStart}needs%{codeEnd} relationships are met, which speeds up your pipelines.',
),
secondDescription: __(
"If you add %{codeStart}needs%{codeEnd} to jobs in your pipeline you'll be able to view the %{codeStart}needs%{codeEnd} relationships between jobs in this tab as a %{linkStart}Directed Acyclic Graph (DAG)%{linkEnd}.",
"If you add %{codeStart}needs%{codeEnd} to jobs in your pipeline you'll be able to view the %{codeStart}needs%{codeEnd} dependencies between jobs in this tab.",
),
button: __('Learn more about Needs relationships'),
button: __('Learn more about needs dependencies'),
},
computed: {
failure() {

View File

@ -7,7 +7,6 @@ class Groups::BoardsController < Groups::ApplicationController
before_action do
push_frontend_feature_flag(:board_multi_select, group)
push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, group)
end
feature_category :team_planning

View File

@ -7,7 +7,6 @@ class Projects::BoardsController < Projects::ApplicationController
before_action :check_issues_available!
before_action do
push_frontend_feature_flag(:board_multi_select, project)
push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project)
end
feature_category :team_planning

View File

@ -48,7 +48,6 @@ class Projects::IssuesController < Projects::ApplicationController
push_frontend_feature_flag(:issues_grid_view)
push_frontend_feature_flag(:service_desk_ticket)
push_frontend_feature_flag(:issues_list_drawer, project)
push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project)
push_frontend_feature_flag(:notifications_todos_buttons, current_user)
end
@ -66,7 +65,6 @@ class Projects::IssuesController < Projects::ApplicationController
push_force_frontend_feature_flag(:work_items_beta, project&.work_items_beta_feature_flag_enabled?)
push_force_frontend_feature_flag(:work_items_alpha, project&.work_items_alpha_feature_flag_enabled?)
push_frontend_feature_flag(:epic_widget_edit_confirmation, project)
push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project)
push_frontend_feature_flag(:namespace_level_work_items, project&.group)
end

View File

@ -38,7 +38,7 @@ module Mutations
:replace_ids
end
response = ::Issues::SetCrmContactsService.new(project: project, current_user: current_user, params: { attribute_name => contact_ids })
response = ::Issues::SetCrmContactsService.new(container: project, current_user: current_user, params: { attribute_name => contact_ids })
.execute(issue)
{

View File

@ -14,7 +14,7 @@ module PlanLimitsHelper
when :ci_pipeline_schedules
s_('AdminSettings|Maximum number of pipeline schedules')
when :ci_needs_size_limit
s_('AdminSettings|Maximum number of DAG dependencies that a job can have')
s_('AdminSettings|Maximum number of needs dependencies that a job can have')
when :ci_registered_group_runners
s_('AdminSettings|Maximum number of runners registered per group')
when :ci_registered_project_runners

View File

@ -40,6 +40,10 @@ class BaseContainerService
end
strong_memoize_attr :project_group
def root_ancestor
project_group&.root_ancestor || group&.root_ancestor
end
private
def handle_container_type(container)

View File

@ -301,7 +301,7 @@ class IssuableBaseService < ::BaseContainerService
def set_crm_contacts(issuable, add_crm_contact_emails, remove_crm_contact_emails = [])
return unless add_crm_contact_emails.present? || remove_crm_contact_emails.present?
::Issues::SetCrmContactsService.new(project: project, current_user: current_user, params: { add_emails: add_crm_contact_emails, remove_emails: remove_crm_contact_emails }).execute(issuable)
::Issues::SetCrmContactsService.new(container: project, current_user: current_user, params: { add_emails: add_crm_contact_emails, remove_emails: remove_crm_contact_emails }).execute(issuable)
end
def before_create(issuable)

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module Issues
class SetCrmContactsService < ::BaseProjectService
class SetCrmContactsService < ::BaseContainerService
MAX_ADDITIONAL_CONTACTS = 6
# Replacing contacts by email is not currently supported
@ -52,7 +52,7 @@ module Issues
end
def add_by_email
contact_ids = ::CustomerRelations::Contact.find_ids_by_emails(project_group.root_ancestor, emails(:add_emails))
contact_ids = ::CustomerRelations::Contact.find_ids_by_emails(container.root_ancestor, emails(:add_emails))
add_by_id(contact_ids)
end

View File

@ -114,7 +114,7 @@
.form-group
= f.label :ci_needs_size_limit, plan_limit_setting_description(:ci_needs_size_limit)
= f.number_field :ci_needs_size_limit, class: 'form-control gl-form-input'
.form-text.text-muted= s_('AdminSettings|This limit cannot be disabled. Set to 0 to block all DAG dependencies.')
.form-text.text-muted= s_('AdminSettings|This limit cannot be disabled. Set to 0 to block all job (needs) dependencies.')
.form-group
= f.label :ci_registered_group_runners, plan_limit_setting_description(:ci_registered_group_runners)
= f.number_field :ci_registered_group_runners, class: 'form-control gl-form-input'

View File

@ -13,11 +13,7 @@ module Gitlab
importer.execute
if Feature.enabled?(:bitbucket_cloud_convert_mentions_to_users, project.creator)
return ImportUsersWorker.perform_async(project.id)
end
ImportPullRequestsWorker.perform_async(project.id)
ImportUsersWorker.perform_async(project.id)
end
def importer_class

View File

@ -1,8 +0,0 @@
---
name: display_work_item_epic_issue_sidebar
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135480
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/430337
milestone: '16.8'
type: development
group: group::product planning
default_enabled: false

View File

@ -1,9 +0,0 @@
---
name: bitbucket_cloud_convert_mentions_to_users
feature_issue_url:
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144923
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/442484
milestone: '16.10'
group: group::import and integrate
type: gitlab_com_derisk
default_enabled: false

View File

@ -824,12 +824,6 @@ Gitlab.ee do
Settings.cron_jobs['sync_service_token_worker'] ||= {}
Settings.cron_jobs['sync_service_token_worker']['cron'] ||= "#{rand(60)} #{rand(5..6)} * * * UTC"
Settings.cron_jobs['sync_service_token_worker']['job_class'] = '::CloudConnector::SyncServiceTokenWorker'
Settings.cron_jobs['llm_embedding_gitlab_documentation_create_embeddings_records_worker'] ||= {}
Settings.cron_jobs['llm_embedding_gitlab_documentation_create_embeddings_records_worker']['cron'] ||= '0 5 * * 1,2,3,4,5'
Settings.cron_jobs['llm_embedding_gitlab_documentation_create_embeddings_records_worker']['job_class'] ||= 'Llm::Embedding::GitlabDocumentation::CreateEmbeddingsRecordsWorker'
Settings.cron_jobs['llm_embedding_gitlab_documentation_cleanup_previous_versions_records_worker'] ||= {}
Settings.cron_jobs['llm_embedding_gitlab_documentation_cleanup_previous_versions_records_worker']['cron'] ||= '0 0 * * *'
Settings.cron_jobs['llm_embedding_gitlab_documentation_cleanup_previous_versions_records_worker']['job_class'] ||= 'Llm::Embedding::GitlabDocumentation::CleanupPreviousVersionsRecordsWorker'
Settings.cron_jobs['users_create_statistics_worker'] ||= {}
Settings.cron_jobs['users_create_statistics_worker']['cron'] ||= '2 15 * * *'
Settings.cron_jobs['users_create_statistics_worker']['job_class'] = 'Users::CreateStatisticsWorker'

View File

@ -463,10 +463,6 @@
- 2
- - llm_completion
- 1
- - llm_embedding_gitlab_documentation_create_db_embeddings_per_doc_file
- 1
- - llm_embedding_gitlab_documentation_set_embeddings_on_the_record
- 1
- - llm_namespace_access_cache_reset
- 1
- - llm_vertex_ai_access_token_refresh

View File

@ -5,6 +5,8 @@ PIPELINE_CHANGES_MESSAGE = <<~MSG
This merge request contains changes to the pipeline configuration for the GitLab project.
Please run `spec/dot_gitlab_ci/job_dependency_spec.rb` locally to confirm that the configuration is valid. This test can be slow and is quarantined in CI for now.
Please consider the effect of the changes in this merge request on the following:
- Effects on different [pipeline types](https://docs.gitlab.com/ee/development/pipelines/index.html#pipelines-types-for-merge-requests)
- Effects on non-canonical projects:

View File

@ -0,0 +1,43 @@
# frozen_string_literal: true
class CleanupBigintConversionsForPCiBuildsAttempt2 < Gitlab::Database::Migration[2.2]
include Gitlab::Database::SchemaHelpers
milestone '17.3'
enable_lock_retries!
TABLE_NAME = :p_ci_builds
TRIGGER_NAME = :trigger_10ee1357e825
COLUMN_NAMES = %i[
auto_canceled_by_id
commit_id
erased_by_id
project_id
runner_id
trigger_request_id
upstream_pipeline_id
user_id
]
def up
return unless trigger_and_integer_columns_exists?
lock_tables(TABLE_NAME, mode: :access_exclusive, only: true)
lock_tables(TABLE_NAME, mode: :access_exclusive)
cleanup_conversion_of_integer_to_bigint(TABLE_NAME, COLUMN_NAMES)
end
def down
return if trigger_and_integer_columns_exists?
restore_conversion_of_integer_to_bigint(TABLE_NAME, COLUMN_NAMES)
end
private
def trigger_and_integer_columns_exists?
trigger_exists?(TABLE_NAME, TRIGGER_NAME) && \
COLUMN_NAMES.all? { |name| column_exists?(TABLE_NAME, "#{name}_convert_to_bigint") }
end
end

View File

@ -0,0 +1 @@
3b33d9061546cc040f69ff79fbe381cb4578ef134143281ee85e2547933f551e

View File

@ -841,22 +841,6 @@ RETURN NEW;
END
$$;
CREATE FUNCTION trigger_10ee1357e825() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW."auto_canceled_by_id_convert_to_bigint" := NEW."auto_canceled_by_id";
NEW."commit_id_convert_to_bigint" := NEW."commit_id";
NEW."erased_by_id_convert_to_bigint" := NEW."erased_by_id";
NEW."project_id_convert_to_bigint" := NEW."project_id";
NEW."runner_id_convert_to_bigint" := NEW."runner_id";
NEW."trigger_request_id_convert_to_bigint" := NEW."trigger_request_id";
NEW."upstream_pipeline_id_convert_to_bigint" := NEW."upstream_pipeline_id";
NEW."user_id_convert_to_bigint" := NEW."user_id";
RETURN NEW;
END;
$$;
CREATE FUNCTION trigger_13d4aa8fe3dd() RETURNS trigger
LANGUAGE plpgsql
AS $$
@ -2172,23 +2156,17 @@ CREATE TABLE p_ci_builds (
created_at timestamp without time zone,
updated_at timestamp without time zone,
started_at timestamp without time zone,
runner_id_convert_to_bigint integer,
coverage double precision,
commit_id_convert_to_bigint integer,
name character varying,
options text,
allow_failure boolean DEFAULT false NOT NULL,
stage character varying,
trigger_request_id_convert_to_bigint integer,
stage_idx integer,
tag boolean,
ref character varying,
user_id_convert_to_bigint integer,
type character varying,
target_url character varying,
description character varying,
project_id_convert_to_bigint integer,
erased_by_id_convert_to_bigint integer,
erased_at timestamp without time zone,
artifacts_expire_at timestamp without time zone,
environment character varying,
@ -2197,13 +2175,11 @@ CREATE TABLE p_ci_builds (
queued_at timestamp without time zone,
lock_version integer DEFAULT 0,
coverage_regex character varying,
auto_canceled_by_id_convert_to_bigint integer,
retried boolean,
protected boolean,
failure_reason integer,
scheduled_at timestamp with time zone,
token_encrypted character varying,
upstream_pipeline_id_convert_to_bigint integer,
resource_group_id bigint,
waiting_for_resource_at timestamp with time zone,
processed boolean,
@ -7497,23 +7473,17 @@ CREATE TABLE ci_builds (
created_at timestamp without time zone,
updated_at timestamp without time zone,
started_at timestamp without time zone,
runner_id_convert_to_bigint integer,
coverage double precision,
commit_id_convert_to_bigint integer,
name character varying,
options text,
allow_failure boolean DEFAULT false NOT NULL,
stage character varying,
trigger_request_id_convert_to_bigint integer,
stage_idx integer,
tag boolean,
ref character varying,
user_id_convert_to_bigint integer,
type character varying,
target_url character varying,
description character varying,
project_id_convert_to_bigint integer,
erased_by_id_convert_to_bigint integer,
erased_at timestamp without time zone,
artifacts_expire_at timestamp without time zone,
environment character varying,
@ -7522,13 +7492,11 @@ CREATE TABLE ci_builds (
queued_at timestamp without time zone,
lock_version integer DEFAULT 0,
coverage_regex character varying,
auto_canceled_by_id_convert_to_bigint integer,
retried boolean,
protected boolean,
failure_reason integer,
scheduled_at timestamp with time zone,
token_encrypted character varying,
upstream_pipeline_id_convert_to_bigint integer,
resource_group_id bigint,
waiting_for_resource_at timestamp with time zone,
processed boolean,
@ -31776,8 +31744,6 @@ CREATE TRIGGER trigger_0da002390fdc BEFORE INSERT OR UPDATE ON operations_featur
CREATE TRIGGER trigger_0e13f214e504 BEFORE INSERT OR UPDATE ON merge_request_assignment_events FOR EACH ROW EXECUTE FUNCTION trigger_0e13f214e504();
CREATE TRIGGER trigger_10ee1357e825 BEFORE INSERT OR UPDATE ON p_ci_builds FOR EACH ROW EXECUTE FUNCTION trigger_10ee1357e825();
CREATE TRIGGER trigger_13d4aa8fe3dd BEFORE INSERT OR UPDATE ON draft_notes FOR EACH ROW EXECUTE FUNCTION trigger_13d4aa8fe3dd();
CREATE TRIGGER trigger_174b23fa3dfb BEFORE INSERT OR UPDATE ON approval_project_rules_users FOR EACH ROW EXECUTE FUNCTION trigger_174b23fa3dfb();

View File

@ -53,7 +53,6 @@ exceptions:
- CVS
- CVSS
- CWE
- DAG
- DAST
- DDL
- DHCP

View File

@ -939,6 +939,7 @@ SSDs
SSGs
Stackdriver
Stackprof
stageless
starrer
starrers
storable

View File

@ -76,7 +76,7 @@ can choose a custom limit. For example, to set the limit to `100`:
Plan.default.actual_limits.update!(ci_needs_size_limit: 100)
```
To disable directed acyclic graphs (DAG), set the limit to `0`. Pipelines with jobs
To disable `needs` dependencies, set the limit to `0`. Pipelines with jobs
configured to use `needs` then return the error `job can only need 0 others`.
## Change maximum scheduled pipeline frequency

View File

@ -260,7 +260,7 @@ from the Admin area:
- **Total number of jobs in currently active pipelines**
- **Maximum number of pipeline subscriptions to and from a project**
- **Maximum number of pipeline schedules**
- **Maximum number of DAG dependencies that a job can have**
- **Maximum number of needs dependencies that a job can have**
- **Maximum number of runners registered per group**
- **Maximum number of runners registered per project**
- **Maximum number of downstream pipelines in a pipeline's hierarchy tree**

View File

@ -39048,6 +39048,7 @@ Attributes for defining a CI/CD variable.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="complianceframeworkfiltersid"></a>`id` | [`ComplianceManagementFrameworkID`](#compliancemanagementframeworkid) | ID of the compliance framework. |
| <a id="complianceframeworkfiltersids"></a>`ids` | [`[ComplianceManagementFrameworkID!]`](#compliancemanagementframeworkid) | IDs of the compliance framework. |
| <a id="complianceframeworkfiltersnot"></a>`not` | [`NegatedComplianceFrameworkFilters`](#negatedcomplianceframeworkfilters) | Negated compliance framework filter input. |
| <a id="complianceframeworkfilterspresencefilter"></a>`presenceFilter` | [`ComplianceFrameworkPresenceFilter`](#complianceframeworkpresencefilter) | Checks presence of compliance framework of the project, "none" and "any" values are supported. |
@ -39292,6 +39293,7 @@ A year and month input for querying product analytics usage data.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="negatedcomplianceframeworkfiltersid"></a>`id` | [`ComplianceManagementFrameworkID`](#compliancemanagementframeworkid) | ID of the compliance framework. |
| <a id="negatedcomplianceframeworkfiltersids"></a>`ids` | [`[ComplianceManagementFrameworkID!]`](#compliancemanagementframeworkid) | IDs of the compliance framework. |
### `NegatedEpicBoardIssueInput`

View File

@ -47,6 +47,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"active" : true,
"created_at" : "2021-01-20T22:11:48.151Z",
"revoked" : false,
"last_used_at": null,
"access_level": 40
},
{
@ -60,6 +61,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"active" : false,
"created_at" : "2021-01-21T12:12:38.123Z",
"revoked" : true,
"last_used_at": "2021-02-13T10:34:57.178Z",
"access_level": 40
}
]

View File

@ -2791,7 +2791,7 @@ paths:
format: int32
ci_needs_size_limit:
type: integer
description: Maximum number of DAG dependencies that a job can have
description: Maximum number of needs dependencies that a job can have
format: int32
ci_registered_group_runners:
type: integer

View File

@ -59744,7 +59744,7 @@ definitions:
ci_needs_size_limit:
type: integer
format: int32
description: Maximum number of DAG dependencies that a job can have
description: Maximum number of needs dependencies that a job can have
ci_registered_group_runners:
type: integer
format: int32

View File

@ -77,7 +77,7 @@ PUT /application/plan_limits
| `ci_active_jobs` | integer | no | Total number of jobs in currently active pipelines. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85895) in GitLab 15.0. |
| `ci_project_subscriptions` | integer | no | Maximum number of pipeline subscriptions to and from a project. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85895) in GitLab 15.0. |
| `ci_pipeline_schedules` | integer | no | Maximum number of pipeline schedules. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85895) in GitLab 15.0. |
| `ci_needs_size_limit` | integer | no | Maximum number of [DAG](../ci/directed_acyclic_graph/index.md) dependencies that a job can have. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85895) in GitLab 15.0. |
| `ci_needs_size_limit` | integer | no | Maximum number of [`needs`](../ci/directed_acyclic_graph/index.md) dependencies that a job can have. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85895) in GitLab 15.0. |
| `ci_registered_group_runners` | integer | no | Maximum number of runners registered per group. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85895) in GitLab 15.0. |
| `ci_registered_project_runners` | integer | no | Maximum number of runners registered per project. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85895) in GitLab 15.0. |
| `dotenv_size` | integer | no | Maximum size of a dotenv artifact in bytes. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/432529) in GitLab 17.1. |

View File

@ -46,8 +46,9 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"id" : 42,
"active" : true,
"created_at" : "2021-01-20T22:11:48.151Z",
"last_used_at" : null,
"revoked" : false,
"access_level": 40
"access_level" : 40
},
{
"user_id" : 141,
@ -60,7 +61,8 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"active" : false,
"created_at" : "2021-01-21T12:12:38.123Z",
"revoked" : true,
"access_level": 40
"last_used_at" : "2021-02-13T10:34:57.178Z",
"access_level" : 40
}
]
```

View File

@ -4,26 +4,26 @@ group: Pipeline Authoring
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
---
# Directed Acyclic Graph
# Make jobs start earlier with `needs`
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
A [directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph) can be
used in the context of a CI/CD pipeline to build relationships between jobs such that
execution is performed in the quickest possible manner, regardless how stages may
be set up.
You can use the [`needs`](../yaml/index.md#needs) keyword to create dependencies between jobs
in a pipeline. Jobs run as soon as their dependencies are met, regardless of the pipeline's `stages`
configuration. You can even configure a pipeline with no stages defined (effectively one large stage)
and jobs still run in the proper order. This pipeline structure is a kind of
[directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph).
For example, you may have a specific tool or separate website that is built
as part of your main project. Using a DAG, you can specify the relationship between
as part of your main project. Using `needs`, you can specify dependencies between
these jobs and GitLab executes the jobs as soon as possible instead of waiting
for each stage to complete.
Unlike other DAG solutions for CI/CD, GitLab does not require you to choose one or the
other. You can implement a hybrid combination of DAG and traditional
stage-based operation within a single pipeline. Configuration is kept very simple,
requiring a single keyword to enable the feature for any job.
Unlike other solutions for CI/CD, GitLab does not require you to choose between staged
or stageless execution flow. You can implement a hybrid combination of staged and stageless
in a single pipeline, using only the `needs` keyword to enable the feature for any job.
Consider a monorepo as follows:
@ -34,7 +34,7 @@ Consider a monorepo as follows:
./service_d
```
It has a pipeline that looks like the following:
This project could have a pipeline organized into three stages:
| build | test | deploy |
|-----------|----------|--------|
@ -43,45 +43,44 @@ It has a pipeline that looks like the following:
| `build_c` | `test_c` | `deploy_c` |
| `build_d` | `test_d` | `deploy_d` |
Using a DAG, you can relate the `_a` jobs to each other separately from the `_b` jobs,
and even if service `a` takes a very long time to build, service `b` doesn't
wait for it and finishes as quickly as it can. In this very same pipeline, `_c` and
`_d` can be left alone and run together in staged sequence just like any standard
GitLab pipeline.
You can improve job execution by using `needs` to relate the `a` jobs to each other
separately from the `b`, `c`, and `d` jobs. `build_a` could take a very long time to build,
but `test_b` doesn't need to wait, it can be configured to start as soon as `build_b` is finished,
which could be much faster.
If desired, `c` and `d` jobs can be left to run in stage sequence.
The `needs` keyword also works with the [parallel](../yaml/index.md#parallel) keyword,
giving you powerful options for parallelization in your pipeline.
## Use cases
A DAG can help solve several different kinds of relationships between jobs within
a CI/CD pipeline. Most typically this would cover when jobs need to fan in or out,
and/or merge back together (diamond dependencies). This can happen when you're
handling multi-platform builds or complex webs of dependencies as in something like
an operating system build or a complex deployment graph of independently deployable
but related microservices.
You can use the [`needs`](../yaml/index.md#needs) keyword to define several different kinds of
dependencies between jobs in a CI/CD pipeline. You can set dependencies to fan in or out,
and even merge back together (diamond dependencies). These dependencies could be used for
pipelines that:
Additionally, a DAG can help with general speediness of pipelines and helping
to deliver fast feedback. By creating dependency relationships that don't unnecessarily
- Handle multi-platform builds.
- Have a complex web of dependencies like an operating system build.
- Have a deployment graph of independently deployable but related microservices.
Additionally, `needs` can help improve the overall speed of pipelines and provide fast feedback.
By creating dependencies that don't unnecessarily
block each other, your pipelines run as quickly as possible regardless of
pipeline stages, ensuring output (including errors) is available to developers
as quickly as possible.
## Usage
<!--- start_remove The following content will be removed on remove_date: '2024-12-19' -->
## Needs dependency visualization (deprecated)
Relationships are defined between jobs using the [`needs` keyword](../yaml/index.md#needs).
WARNING:
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/336560) in GitLab 17.1
and is planned for removal in 17.4. View `needs` relationships in the
[full pipeline graph](../pipelines/index.md#group-jobs-by-stage-or-needs-configuration) instead.
The `needs` keyword also works with the [parallel](../yaml/index.md#parallel) keyword,
giving you powerful options for parallelization within your pipeline.
## Limitations
A directed acyclic graph is a complicated feature, and as of the initial MVC there
are certain use cases that you may need to work around. For more information, check the:
- [`needs` additional details](../yaml/index.md#needs).
- Related epic [tracking planned improvements](https://gitlab.com/groups/gitlab-org/-/epics/1716).
## Needs Visualization
The needs visualization makes it easier to visualize the relationships between dependent jobs in a DAG. This graph displays all the jobs in a pipeline that need or are needed by other jobs. Jobs with no relationships are not displayed in this view.
The needs dependency visualization makes it easier to visualize the dependencies
between jobs in a pipeline. This graph displays all the jobs in a pipeline
that need or are needed by other jobs. Jobs with no dependencies are not displayed in this view.
To see the needs visualization, select **Needs** when viewing a pipeline that uses the `needs` keyword.
@ -90,5 +89,4 @@ To see the needs visualization, select **Needs** when viewing a pipeline that us
Selecting a node highlights all the job paths it depends on.
![Needs visualization with path highlight](img/dag_graph_example_clicked_v13_1.png)
You can also see `needs` relationships in [full pipeline graphs](../pipelines/index.md#group-jobs-by-stage-or-needs-configuration).
<!--- end_remove -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

@ -45,7 +45,7 @@ Pipelines can be configured in many different ways:
- [Basic pipelines](pipeline_architectures.md#basic-pipelines) run everything in each stage concurrently,
followed by the next stage.
- [Directed Acyclic Graph Pipeline (DAG) pipelines](../directed_acyclic_graph/index.md) are based on relationships
- [Pipelines that use the `needs` keyword](../directed_acyclic_graph/index.md) run based on dependencies
between jobs and can run more quickly than basic pipelines.
- [Merge request pipelines](../pipelines/merge_request_pipelines.md) run for merge
requests only (rather than for every commit).
@ -399,9 +399,7 @@ by stage configuration, select **stage** in the **Group jobs by** section:
![jobs grouped by stage](img/pipeline_stage_view_v16_11.png)
To group the jobs by [`needs`](../yaml/index.md#needs) configuration, select **Job dependencies**.
You can optionally select **Show dependencies** to render lines between dependent jobs,
similar to the [`needs` visualization](../directed_acyclic_graph/index.md#needs-visualization)
in the pipeline editor:
You can optionally select **Show dependencies** to render lines between dependent jobs.
![jobs grouped by job dependencies](img/pipeline_dependency_view_v16_11.png)

View File

@ -17,7 +17,7 @@ You can structure your pipelines with different methods, each with their
own advantages. These methods can be mixed and matched if needed:
- [Basic](#basic-pipelines): Good for straightforward projects where all the configuration is in one place.
- [Directed Acyclic Graph](#directed-acyclic-graph-pipelines): Good for large, complex projects that need efficient execution.
- [Pipelines with the `needs` keyword](#pipelines-with-the-needs-keyword): Good for large, complex projects that need efficient execution.
- [Parent-child pipelines](#parent-child-pipelines): Good for monorepos and projects with lots of independently defined components.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
@ -116,13 +116,12 @@ deploy_b:
environment: production
```
## Directed Acyclic Graph Pipelines
## Pipelines with the `needs` keyword
If efficiency is important to you and you want everything to run as quickly as possible,
you can use [Directed Acyclic Graphs (DAG)](../directed_acyclic_graph/index.md). Use the
[`needs` keyword](../yaml/index.md#needs) to define dependency relationships between
your jobs. When GitLab knows the relationships between your jobs, it can run everything
as fast as possible, and even skips into subsequent stages when possible.
If efficiency is important and you want everything to run as quickly as possible,
you can use the [`needs` keyword](../directed_acyclic_graph/index.md) to define dependencies
between your jobs. When GitLab knows the dependencies between your jobs,
jobs can run as fast as possible, even starting earlier than other jobs in the same stage.
In the example below, if `build_a` and `test_a` are much faster than `build_b` and
`test_b`, GitLab starts `deploy_a` even if `build_b` is still running.
@ -130,16 +129,16 @@ In the example below, if `build_a` and `test_a` are much faster than `build_b` a
```mermaid
%%{init: { "fontFamily": "GitLab Sans" }}%%
graph LR
accTitle: Pipeline using DAG
accTitle: Pipeline using needs
accDescr: Shows how two jobs can start without waiting for earlier stages to complete
subgraph Pipeline using DAG
subgraph Pipeline using needs
build_a --> test_a --> deploy_a
build_b --> test_b --> deploy_b
end
```
Example DAG `/.gitlab-ci.yml` configuration matching the diagram:
Example `/.gitlab-ci.yml` configuration matching the diagram:
```yaml
stages:
@ -208,7 +207,7 @@ YAML is dynamically generated.
![Parent pipeline graph expanded](img/parent_pipeline_graph_expanded_v14_3.png)
In the [basic pipeline](#basic-pipelines) and [directed acyclic graph](#directed-acyclic-graph-pipelines)
In the [basic pipeline](#basic-pipelines) and [`needs` pipeline](#pipelines-with-the-needs-keyword)
examples above, there are two packages that could be built independently.
These cases are ideal for using [parent-child pipelines](downstream_pipelines.md#parent-child-pipelines).
It separates out the configuration into multiple files, keeping things simpler.
@ -218,7 +217,7 @@ You can combine parent-child pipelines with:
when there are changes to that area.
- The [`include` keyword](../yaml/index.md#include): Bring in common behaviors, ensuring
you are not repeating yourself.
- [DAG pipelines](#directed-acyclic-graph-pipelines) inside of child pipelines, achieving the benefits of both.
- The [`needs` keyword](#pipelines-with-the-needs-keyword) inside of child pipelines, achieving the benefits of both.
```mermaid
%%{init: { "fontFamily": "GitLab Sans" }}%%
@ -263,7 +262,7 @@ trigger_b:
```
Example child `a` pipeline configuration, located in `/a/.gitlab-ci.yml`, making
use of the DAG `needs` keyword:
use of the `needs` keyword:
```yaml
stages:
@ -294,7 +293,7 @@ deploy_a:
```
Example child `b` pipeline configuration, located in `/b/.gitlab-ci.yml`, making
use of the DAG `needs` keyword:
use of the `needs` keyword:
```yaml
stages:

View File

@ -34,7 +34,7 @@ heavily influenced by the:
- [Size of the repository](../../user/project/repository/monorepos/index.md)
- Total number of stages and jobs.
- Dependencies between jobs.
- The ["critical path"](#directed-acyclic-graphs-dag-visualization), which represents
- The ["critical path"](#needs-dependency-visualization), which represents
the minimum and maximum pipeline duration.
Additional points to pay attention relate to [GitLab Runners](../runners/index.md):
@ -89,12 +89,10 @@ running simultaneously to support the parallel jobs.
The [testing levels for GitLab](../../development/testing_guide/testing_levels.md)
provide an example of a complex testing strategy with many components involved.
### Directed Acyclic Graphs (DAG) visualization
### `needs` dependency visualization
The [Directed Acyclic Graph](../directed_acyclic_graph/index.md) (DAG) visualization can help analyze the critical path in
the pipeline and understand possible blockers.
![CI Pipeline Critical Path with DAG](img/ci_efficiency_pipeline_dag_critical_path.png)
Viewing the `needs` dependencies in the [full pipeline graph](../pipelines/index.md#group-jobs-by-stage-or-needs-configuration)
can help analyze the critical path in the pipeline and understand possible blockers.
### Pipeline Monitoring
@ -185,11 +183,11 @@ Decide if it's important for long jobs to run early, before fast feedback from
faster jobs. The initial failures may make it clear that the rest of the pipeline
shouldn't run, saving pipeline resources.
### Directed Acyclic Graphs (DAG)
### `needs` keyword
In a basic configuration, jobs always wait for all other jobs in earlier stages to complete
before running. This is the simplest configuration, but it's also the slowest in most
cases. [Directed Acyclic Graphs](../directed_acyclic_graph/index.md) and
cases. [Pipelines with the `needs` keyword](../directed_acyclic_graph/index.md) and
[parent/child pipelines](downstream_pipelines.md#parent-child-pipelines) are more flexible and can
be more efficient, but can also make pipelines harder to understand and analyze.

View File

@ -147,8 +147,8 @@ For the complete `.gitlab-ci.yml` syntax, see the full [CI/CD YAML syntax refere
- Each job contains a script section and belongs to a stage:
- [`stage`](../yaml/index.md#stage) describes the sequential execution of jobs.
If there are runners available, jobs in a single stage run in parallel.
- Use the [`needs` keyword](../yaml/index.md#needs) to run jobs out of stage order.
This creates a [Directed Acyclic Graph (DAG)](../directed_acyclic_graph/index.md).
- Use the [`needs` keyword](../yaml/index.md#needs) to [run jobs out of stage order](../directed_acyclic_graph/index.md),
to increase pipeline speed and efficiency.
- You can set additional configuration to customize how your jobs and stages perform:
- Use the [`rules`](../yaml/index.md#rules) keyword to specify when to run or skip jobs.
The `only` and `except` legacy keywords are still supported, but can't be used

View File

@ -38,29 +38,33 @@ called `Gitlab::BitbucketImport::AdvanceStageWorker`.
This worker imports the repository, wiki and labels, scheduling the next stage when
done.
### 2. Stage::ImportPullRequestsWorker
### 2. Stage::ImportUsersWorker
This worker imports members of the source Bitbucket Cloud workspace.
### 3. Stage::ImportPullRequestsWorker
This worker imports all pull requests. For every pull request, a job for the
`Gitlab::BitbucketImport::ImportPullRequestWorker` worker is scheduled.
### 3. Stage::ImportPullRequestsNotesWorker
### 4. Stage::ImportPullRequestsNotesWorker
This worker imports notes (comments) for all merge requests.
For every merge request, a job for the `Gitlab::BitbucketImport::ImportPullRequestNotesWorker` worker is scheduled which imports all notes for the merge request.
### 4. Stage::ImportIssuesWorker
### 5. Stage::ImportIssuesWorker
This worker imports all issues. For every issue, a job for the
`Gitlab::BitbucketImport::ImportIssueWorker` worker is scheduled.
### 5. Stage::ImportIssuesNotesWorker
### 6. Stage::ImportIssuesNotesWorker
This worker imports notes (comments) for all issues.
For every issue, a job for the `Gitlab::BitbucketImport::ImportIssueNotesWorker` worker is scheduled which imports all notes for the issue.
### 5. Stage::FinishImportWorker
### 7. Stage::FinishImportWorker
This worker completes the import process by performing some housekeeping
such as marking the import as completed.

View File

@ -54,7 +54,7 @@ processing it, and returns any syntax or semantic errors. The `YAML Processor` c
The `CreatePipelineService` receives the abstract data structure returned by the `YAML Processor`,
which then converts it to persisted models (like pipeline, stages, and jobs). After that, the pipeline is ready
to be processed. Processing a pipeline means running the jobs in order of execution (stage or DAG)
to be processed. Processing a pipeline means running the jobs in order of execution (stage or `needs`)
until either one of the following:
- All expected jobs have been executed.
@ -109,7 +109,7 @@ A job with the `created` state isn't seen by the runner yet. To make it possible
1. The job is created in the very first stage of the pipeline.
1. The job required a manual start and it has been triggered.
1. All jobs from the previous stage have completed successfully. In this case we transition all jobs from the next stage to `pending`.
1. The job specifies DAG dependencies using `needs:` and all the dependent jobs are completed.
1. The job specifies needs dependencies using `needs:` and all the dependent jobs are completed.
1. The job has not been [dropped](#dropping-stuck-builds) because of its not-runnable state by [`Ci::PipelineCreation::DropNotRunnableBuildsService`](https://gitlab.com/gitlab-org/gitlab/-/blob/v16.0.4-ee/ee/app/services/ci/pipeline_creation/drop_not_runnable_builds_service.rb).
When the runner is connected, it requests the next `pending` job to run by polling the server continuously.

View File

@ -1290,24 +1290,25 @@ Verify your feature appears in `gon.licensed_features` in the browser console.
EE licensed features that enhance existing functionality in the UI add new
elements or interactions to your Vue application as components.
To separate template differences, use a child EE component to separate Vue template differences.
You must import the EE component [asynchronously](https://v2.vuejs.org/v2/guide/components-dynamic-async.html#Async-Components).
You can import EE components inside CE components to add EE features.
This allows GitLab to load the correct component in EE, while in CE GitLab loads an empty component
that renders nothing. This code **must** exist in the CE repository, in addition to the EE repository.
Use an `ee_component` alias to import an EE component. In EE the `ee_component` import alias points
to the `ee/app/assets/javascripts` directory. While in CE this alias will be resolved to an empty
component that renders nothing.
A CE component acts as the entry point to your EE feature. To add a EE component,
locate it the `ee/` directory and add it with `import('ee_component/...')`:
Here is an example of an EE component imported to a CE component:
```html
```vue
<script>
// app/assets/javascripts/feature/components/form.vue
// In EE this will be resolved as `ee/app/assets/javascripts/feature/components/my_ee_component.vue`
// In CE as `app/assets/javascripts/vue_shared/components/empty_component.js`
import MyEeComponent from 'ee_component/feature/components/my_ee_component.vue';
export default {
mixins: [glFeatureFlagMixin()],
components: {
// Import an EE component from CE
MyEeComponent: () => import('ee_component/components/my_ee_component.vue'),
MyEeComponent,
},
};
</script>
@ -1321,10 +1322,15 @@ export default {
</template>
```
NOTE:
An EE component can be imported
[asynchronously](https://v2.vuejs.org/v2/guide/components-dynamic-async.html#Async-Components) if
its rendering within CE codebase relies on some check (e.g. a feature flag check).
Check `glFeatures` to ensure that the Vue components are guarded. The components render only when
the license is present.
```html
```vue
<script>
// ee/app/assets/javascripts/feature/components/special_component.vue
@ -1421,11 +1427,8 @@ export default {
**For EE components that need different results for the same computed values, we can pass in props to the CE wrapper as seen in the example.**
- **EE Child components**
- Since we are using the asynchronous loading to check which component to load, we'd still use the component's name, check [this example](#extend-vue-applications-with-ee-vue-components).
- **EE extra HTML**
- For the templates that have extra HTML in EE we should move it into a new component and use the `ee_else_ce` dynamic import
- For the templates that have extra HTML in EE we should move it into a new component and use the `ee_else_ce` import alias
#### Extend other JS code

View File

@ -1934,3 +1934,106 @@ Example:
```json
{ "op": "Add", "path": "name.formatted", "value": "New Name" }
```
## Namespaces
### Get a namespace by ID
```plaintext
GET /internal/gitlab_subscriptions/namespaces/:id
```
Parameters:
| Attribute | Type | Required | Description |
| --------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | ID or [URL-encoded path of the namespace](../../api/rest/index.md#namespaced-path-encoding) |
Example request:
```shell
curl --request GET --header "PRIVATE-TOKEN: <admin_access_token>" "https://gitlab.com/api/v4/internal/gitlab_subscriptions/namespaces/1"
```
Example response:
```json
{
"id": 1,
"name": "group1",
"path": "group1",
"kind": "group",
"full_path": "group1",
"parent_id": null,
"avatar_url": null,
"web_url": "https://gitlab.example.com/groups/group1",
"members_count_with_descendants": 2,
"billable_members_count": 2,
"max_seats_used": 0,
"seats_in_use": 0,
"plan": "default",
"end_date": null,
"trial_ends_on": null,
"trial": false,
"root_repository_size": 100,
"projects_count": 3
}
```
#### Known consumers
- CustomersDot
### Update a namespace
Use a PUT command to update an existing namespace.
```plaintext
PUT /internal/gitlab_subscriptions/namespaces/:id
```
Parameters:
| Attribute | Type | Required | Description |
| --------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | ID or [URL-encoded path of the namespace](../../api/rest/index.md#namespaced-path-encoding) |
| `shared_runners_minutes_limit` | integer | no | Compute minutes quota |
| `extra_shared_runners_minutes_limit` | integer | no | Extra compute minutes |
| `additional_purchased_storage_size` | integer | no | Additional storage size |
| `additional_purchased_storage_ends_on` | date | no | Additional purchased storage Ends on |
| `gitlab_subscription_attributes` | hash | no | Hash object containing GitLab Subscription attributes. Accepts `seats`,`max_seats_used`,`plan_code`,`end_date`,`auto_renew`,`trial`,`trial_ends_on`,`trial_starts_on`,`trial_extension_type` |
Example request:
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.com/api/v4/internal/gitlab_subscriptions/namespaces/1 --data '{"shared_runners_minutes_limit":1000}'"
```
Example response:
```json
{
"id": 1,
"name": "group1",
"path": "group1",
"kind": "group",
"full_path": "group1",
"parent_id": null,
"avatar_url": null,
"web_url": "https://gitlab.example.com/groups/group1",
"members_count_with_descendants": 2,
"billable_members_count": 2,
"max_seats_used": 0,
"seats_in_use": 0,
"plan": "default",
"end_date": null,
"trial_ends_on": null,
"trial": false,
"root_repository_size": 100,
"projects_count": 3
}
```
#### Known consumers
- CustomersDot

View File

@ -438,7 +438,7 @@ For this scenario, you have to:
Additionally, `scripts/utils.sh` is always downloaded from the API when this pattern is used (this file contains the code for `.fast-no-clone-job`).
#### Runner tags
### Runner tags
On GitLab.com, both unprivileged and privileged runners are
available. For projects in the `gitlab-org` group and forks of those
@ -459,3 +459,87 @@ no matching runners are available.
See [the GitLab Repositories handbook page](https://handbook.gitlab.com/handbook/engineering/gitlab-repositories/#cicd-configuration)
for more information.
### Using the `gitlab` Ruby gem in the canonical project
When calling `require 'gitlab'` in the canonical project, it will require the `lib/gitlab.rb` file when `$LOAD_PATH` has `lib`, which happens when we're loading the application (`config/application.rb`) or tests (`spec/spec_helper.rb`).
This means we're not able to load the `gitlab` gem under the above conditions and even if we can, the constant name will conflict, breaking internal assumptions and causing random errors.
If you are working on a script that is using [the `gitlab` Ruby gem](https://github.com/NARKOZ/gitlab), you will need to take a few precautions:
#### 1 - Conditional require of the gem
To avoid potential conflicts, only require the `gitlab` gem if the `Gitlab` constant isn't defined:
```ruby
# Bad
require 'gitlab'
# Good
if Object.const_defined?(:RSpec)
# Ok, we're testing, we know we're going to stub `Gitlab`, so we just ignore
else
require 'gitlab'
if Gitlab.singleton_class.method_defined?(:com?)
abort 'lib/gitlab.rb is loaded, and this means we can no longer load the client and we cannot proceed'
end
end
```
#### 2 - Mock the `gitlab` gem entirely in your specs
In your specs, `require 'gitlab'` will reference the `lib/gitlab.rb` file:
```ruby
# Bad
allow(GitLab).to receive(:a_method).and_return(...)
# Good
client = double('GitLab')
# In order to easily stub the client, consider using a method to return the client.
# We can then stub the method to return our fake client, which we can further stub its methods.
#
# This is the pattern followed below
let(:instance) { described_class.new }
allow(instance).to receive(:gitlab).and_return(client)
allow(client).to receive(:a_method).and_return(...)
```
In case you need to query jobs for instance, the following snippet will be useful:
```ruby
# Bad
allow(GitLab).to receive(:pipeline_jobs).and_return(...)
# Good
#
# rubocop:disable RSpec/VerifiedDoubles -- We do not load the Gitlab client directly
client = double('GitLab')
allow(instance).to receive(:gitlab).and_return(client)
jobs = ['job1', 'job2']
allow(client).to yield_jobs(:pipeline_jobs, jobs)
def yield_jobs(api_method, jobs)
messages = receive_message_chain(api_method, :auto_paginate)
jobs.inject(messages) do |stub, job_name|
stub.and_yield(double(name: job_name))
end
end
# rubocop:enable RSpec/VerifiedDoubles
```
#### 3 - Do not call your script with `bundle exec`
Executing with `bundle exec` will change the `$LOAD_PATH` for Ruby, and it will load `lib/gitlab.rb` when calling `require 'gitlab'`:
```shell
# Bad
bundle exec scripts/my-script.rb
# Good
scripts/my-script.rb
```

View File

@ -498,7 +498,7 @@ including:
- [Configuration Files](../administration/backup_restore/backup_gitlab.md#storing-configuration-files)
- [Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/snapshot-restore.md)
- [Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/snapshot-restore.html)
GitLab Geo
@ -721,7 +721,7 @@ for self-managed customers that covers topics such as:
- [Operating System Recommendations](hardening_operating_system_recommendations.md)
GitLab CIS Benchmark Guide - GitLab has published a [CIS Benchmark](https://about.gitlab.com/blog/2024/04/17/gitlab-introduces-new-cis-benchmark-for-improved-security/index.md)
GitLab CIS Benchmark Guide - GitLab has published a [CIS Benchmark](https://about.gitlab.com/blog/2024/04/17/gitlab-introduces-new-cis-benchmark-for-improved-security/)
to guide hardening decisions in the application. This may be used in
concert with this guide to harden the environment in accordance with NIST 800-53
controls. Not all suggestions in the CIS Benchmark directly align with

View File

@ -32,7 +32,7 @@ To view the roadmap in a group:
1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Roadmap**.
The Roadmap page shows the epics and milestones in a
The roadmap shows the epics and milestones in a
group, one of its subgroups, or a project in one of the groups.
On the epic bars, you can see each epic's title, progress, and completed weight percentage.
@ -50,7 +50,7 @@ heading to toggle the list of the milestone bars.
![roadmap view](img/roadmap_view_v14_3.png)
## Sort and filter the Roadmap
## Sort and filter the roadmap
> - Filtering by group was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/385191) in GitLab 15.9.
> - Sorting by title, created date, and last updated date [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/460492) in GitLab 17.0.
@ -61,7 +61,7 @@ Filtering roadmaps by milestone might not be available to you. Be sure to review
When you want to explore a roadmap, there are several ways to make it easier by sorting epics or
filtering them by what's important for you.
You can sort epics in the Roadmap view by:
In the Roadmap view, you can sort epics by:
- Start date
- Due date
@ -73,7 +73,7 @@ Each option contains a button that toggles the sort order between **ascending**
and **descending**. The sort option and order persist when browsing Epics, including
the [epics list view](../epics/index.md).
You can also filter epics in the Roadmap view by the epics':
In the Roadmap view, you can also filter by the epics':
- Author
- Label
@ -121,7 +121,7 @@ Roadmap provides these date range options, each with a predetermined timeline du
### Layout presets
Depending on selected [date range preset](#date-range-presets), Roadmap supports
Depending on selected [date range preset](#date-range-presets), the roadmap supports
these layout presets:
- **Quarters**: Available only when the **Within 3 years** date range is selected.

View File

@ -88,7 +88,7 @@ IID. The link to the artifacts can also be accessed from the **Experiment Candid
## View CI information
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119788) in 16.1
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119788) in GitLab 16.1.
Candidates can be associated to the CI job that created them, allowing quick links to the merge request, pipeline, and user that triggered the pipeline:

View File

@ -129,6 +129,11 @@ pre-push:
tags: secrets
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
run: 'if command -v gitleaks > /dev/null 2>&1; then gitleaks detect --log-opts="$(git merge-base origin/master HEAD)..HEAD" --no-banner --redact --verbose; else echo "WARNING: gitleaks is not installed. Please install it. See https://github.com/zricethezav/gitleaks#installing."; fi'
reminder-to-validate-ci-config:
tags: ci config
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
glob: '{.gitlab-ci.yml,.gitlab/**/*.yml}'
run: "echo '🚨WARNING: You are modifying ci pipeline configurations. Please test your changes by running `bundle exec rspec spec/dot_gitlab_ci/job_dependency_spec.rb`. If you think we are missing test coverage for your changes, please add them.'"
scripts:
'merge_conflicts':
@ -156,6 +161,11 @@ pre-commit:
tags: secrets
files: git diff --name-only --diff-filter=d --staged
run: 'if command -v gitleaks > /dev/null 2>&1; then gitleaks protect --no-banner --staged --redact --verbose; else echo "WARNING: gitleaks is not installed. Please install it. See https://github.com/zricethezav/gitleaks#installing."; fi'
reminder-to-validate-ci-config:
tags: ci config
files: git diff --name-only --diff-filter=d --staged
glob: '{.gitlab-ci.yml,.gitlab/**/*.yml}'
run: "echo '🚨WARNING: You are modifying ci pipeline configurations. Please test your changes by running `bundle exec rspec spec/dot_gitlab_ci/job_dependency_spec.rb`. If you think we are missing test coverage for your changes, please add them.'"
auto-fix:
parallel: true

View File

@ -58,7 +58,7 @@ module API
optional :ci_project_subscriptions, type: Integer,
desc: 'Maximum number of pipeline subscriptions to and from a project'
optional :ci_pipeline_schedules, type: Integer, desc: 'Maximum number of pipeline schedules'
optional :ci_needs_size_limit, type: Integer, desc: 'Maximum number of DAG dependencies that a job can have'
optional :ci_needs_size_limit, type: Integer, desc: 'Maximum number of needs dependencies that a job can have'
optional :ci_registered_group_runners, type: Integer, desc: 'Maximum number of runners registered per group'
optional :ci_registered_project_runners, type: Integer, desc: 'Maximum number of runners registered per project'
optional :conan_max_file_size, type: Integer, desc: 'Maximum Conan package file size in bytes'

View File

@ -1233,8 +1233,15 @@ into similar problems in the future (e.g. when new tables are created).
end
end
def lock_tables(*tables, mode: :access_exclusive)
execute("LOCK TABLE #{tables.join(', ')} IN #{mode.to_s.upcase.tr('_', ' ')} MODE")
def lock_tables(*tables, mode: :access_exclusive, only: nil, nowait: nil)
only_param = only && 'ONLY'
nowait_param = nowait && 'NOWAIT'
tables_param = tables.map { |t| quote_table_name(t) }.join(', ')
mode_param = mode.to_s.upcase.tr('_', ' ')
execute(<<~SQL.squish)
LOCK TABLE #{only_param} #{tables_param} IN #{mode_param} MODE #{nowait_param}
SQL
end
private

View File

@ -138,7 +138,7 @@ module Gitlab
klass: self.class,
logger: Gitlab::AppLogger,
connection: connection
).run(&block)
).run(raise_on_exhaustion: true, &block)
end
def table_partitioned?
@ -160,7 +160,7 @@ module Gitlab
primary_transaction(statement_timeout: STATEMENT_TIMEOUT) do
# Running ANALYZE on partitioned table will go through itself and its partitions
connection.execute("ANALYZE #{model.quoted_table_name}")
connection.execute("ANALYZE (SKIP_LOCKED) #{model.quoted_table_name}")
end
end

View File

@ -51,11 +51,8 @@ module Gitlab
end
def pluck_mentions_from_text(text)
gitlab_like_mentions = text.scan(GITLAB_MENTIONS_REGEX)
return gitlab_like_mentions unless Feature.enabled?(:bitbucket_cloud_convert_mentions_to_users, project_creator)
(gitlab_like_mentions + text.scan(BITBUCKET_MENTIONS_REGEX)).flatten
mentions = text.scan(GITLAB_MENTIONS_REGEX) + text.scan(BITBUCKET_MENTIONS_REGEX)
mentions.flatten
end
end
end

View File

@ -4009,9 +4009,6 @@ msgstr ""
msgid "AdminSettings|Maximum includes"
msgstr ""
msgid "AdminSettings|Maximum number of DAG dependencies that a job can have"
msgstr ""
msgid "AdminSettings|Maximum number of Instance-level CI/CD variables that can be defined"
msgstr ""
@ -4024,6 +4021,9 @@ msgstr ""
msgid "AdminSettings|Maximum number of jobs in a single pipeline"
msgstr ""
msgid "AdminSettings|Maximum number of needs dependencies that a job can have"
msgstr ""
msgid "AdminSettings|Maximum number of pipeline schedules"
msgstr ""
@ -4183,7 +4183,7 @@ msgstr ""
msgid "AdminSettings|This cost factor will be applied to the storage consumed by forks."
msgstr ""
msgid "AdminSettings|This limit cannot be disabled. Set to 0 to block all DAG dependencies."
msgid "AdminSettings|This limit cannot be disabled. Set to 0 to block all job (needs) dependencies."
msgstr ""
msgid "AdminSettings|To enable Registration Features, first enable Service Ping."
@ -16378,9 +16378,6 @@ msgstr ""
msgid "CycleAnalytics|seconds"
msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
msgid "DAST configuration not found"
msgstr ""
@ -26896,7 +26893,7 @@ msgstr ""
msgid "If using GitHub, youll see pipeline statuses on GitHub for your commits and pull requests. %{more_info_link}"
msgstr ""
msgid "If you add %{codeStart}needs%{codeEnd} to jobs in your pipeline you'll be able to view the %{codeStart}needs%{codeEnd} relationships between jobs in this tab as a %{linkStart}Directed Acyclic Graph (DAG)%{linkEnd}."
msgid "If you add %{codeStart}needs%{codeEnd} to jobs in your pipeline you'll be able to view the %{codeStart}needs%{codeEnd} dependencies between jobs in this tab."
msgstr ""
msgid "If you are unable to sign in or recover your password, contact a GitLab administrator."
@ -30771,9 +30768,6 @@ msgstr ""
msgid "Learn more about GitLab"
msgstr ""
msgid "Learn more about Needs relationships"
msgstr ""
msgid "Learn more about Service Desk"
msgstr ""
@ -30810,6 +30804,9 @@ msgstr ""
msgid "Learn more about max seats used"
msgstr ""
msgid "Learn more about needs dependencies"
msgstr ""
msgid "Learn more about seats owed"
msgstr ""
@ -34525,6 +34522,9 @@ msgstr ""
msgid "Needs attention"
msgstr ""
msgid "Needs visualization requires at least 3 dependent jobs."
msgstr ""
msgid "Network"
msgstr ""

View File

@ -1,5 +1,8 @@
# frozen_string_literal: true
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
require_relative 'default_options'

View File

@ -1,5 +1,8 @@
# frozen_string_literal: true
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
require_relative 'default_options'

View File

@ -1,5 +1,8 @@
# frozen_string_literal: true
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
require_relative 'default_options'

View File

@ -2,6 +2,9 @@
# frozen_string_literal: true
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
require_relative 'api/default_options'

View File

@ -1,6 +1,9 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
require 'json'

View File

@ -2,6 +2,9 @@
# frozen_string_literal: true
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
require 'optparse'

View File

@ -2,8 +2,11 @@
# frozen_string_literal: true
require 'optparse'
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
require 'optparse'
module Packages
class AutomatedCleanup

View File

@ -11,9 +11,12 @@
# - See https://gitlab.com/gitlab-org/gitlab/-/issues/325640
# - See https://gitlab.com/groups/gitlab-org/-/epics/5670
require 'rubygems'
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
require 'optparse'
require 'rubygems'
class QueryLimitingReport
GITLAB_PROJECT_ID = 278964 # gitlab-org/gitlab project

View File

@ -1,8 +1,17 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
if Object.const_defined?(:RSpec)
# Ok, we're testing, we know we're going to stub `Gitlab`, so we just ignore
else
require 'gitlab'
if Gitlab.singleton_class.method_defined?(:com?)
abort 'lib/gitlab.rb is loaded, and this means we can no longer load the client and we cannot proceed'
end
end
require 'time'
require 'gitlab' unless Object.const_defined?(:Gitlab)
class PreMergeChecks
DEFAULT_API_ENDPOINT = "https://gitlab.com/api/v4"

View File

@ -4,7 +4,16 @@
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab' unless Object.const_defined?(:Gitlab)
if Object.const_defined?(:RSpec)
# Ok, we're testing, we know we're going to stub `Gitlab`, so we just ignore
else
require 'gitlab'
if Gitlab.singleton_class.method_defined?(:com?)
abort 'lib/gitlab.rb is loaded, and this means we can no longer load the client and we cannot proceed'
end
end
require 'net/http'
class SetPipelineName

View File

@ -2,8 +2,11 @@
# frozen_string_literal: true
require 'optparse'
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
require 'optparse'
require_relative File.expand_path('../../tooling/lib/tooling/helm3_client.rb', __dir__)
require_relative File.expand_path('../../tooling/lib/tooling/kubernetes_client.rb', __dir__)

View File

@ -1,8 +1,20 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
#
# In spec/scripts/setup/find_jh_branch_spec.rb we completely stub it
require 'gitlab' unless Object.const_defined?(:Gitlab)
if Object.const_defined?(:RSpec)
# Ok, we're testing, we know we're going to stub `Gitlab`, so we just ignore
else
require 'gitlab'
if Gitlab.singleton_class.method_defined?(:com?)
abort 'lib/gitlab.rb is loaded, and this means we can no longer load the client and we cannot proceed'
end
end
require_relative '../api/default_options'

View File

@ -1,8 +1,21 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
#
# In spec/scripts/setup/generate_as_if_foss_env_spec.rb we completely stub it
require 'gitlab' unless Object.const_defined?(:Gitlab)
if Object.const_defined?(:RSpec)
# Ok, we're testing, we know we're going to stub `Gitlab`, so we just ignore
else
require 'gitlab'
if Gitlab.singleton_class.method_defined?(:com?)
abort 'lib/gitlab.rb is loaded, and this means we can no longer load the client and we cannot proceed'
end
end
require 'set' # rubocop:disable Lint/RedundantRequireStatement -- Ruby 3.1 and earlier needs this. Drop this line after Ruby 3.2+ is only supported.
class GenerateAsIfFossEnv

View File

@ -1,6 +1,9 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
# We need to take some precautions when using the `gitlab` gem in this project.
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
module Trigger

View File

@ -2,9 +2,63 @@
require 'spec_helper'
# ***********************************************************************************************************
# The tests in this file are recommended to run locally to test ci configuration changes
# The test runs quite slowly because our configuration logic is very complex and it takes time to process
# ***********************************************************************************************************
#
# HOW TO CONTRIBUTE
#
# For example, ci rule changes could break gitlab-foss pipelines, as seen in
# https://gitlab.com/gitlab-org/quality/engineering-productivity/master-broken-incidents/-/issues/7356
# we then added test cases by simulating pipeline for gitlab-org/gitlab-foss
# See `with gitlab.com gitlab-org gitlab-foss project` context below for details.
# If you think we are missing important test cases for a pipeline type, please add them following this exmaple.
# ***********************************************************************************************************
RSpec.describe 'ci jobs dependency', feature_category: :tooling,
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/34040#note_1991033499' do
include RepoHelpers
def sync_local_files_to_project(project, user, branch_name, files:)
actions = []
entries = project.repository.tree(branch_name, recursive: true).entries
entries.map! { |e| e.dir? ? project.repository.tree(branch_name, e.path, recursive: true).entries : e }
current_files = entries.flatten.select(&:file?).map(&:path).uniq
# Delete old
actions.concat (current_files - files).map { |file| { action: :delete, file_path: file } }
# Add new
actions.concat (files - current_files).map { |file|
{ action: :create, file_path: file, content: read_file(file) }
}
# Update changed
(current_files & files).each do |file|
content = read_file(file)
if content != project.repository.blob_data_at(branch_name, file)
actions << { action: :update, file_path: file, content: content }
end
end
if actions.any?
puts "Syncing files to #{branch_name} branch"
project.repository.commit_files(user, branch_name: branch_name, message: 'syncing', actions: actions)
else
puts "No file syncing needed"
end
end
def read_file(file, ignore_ci_component: true)
content = File.read(file)
return content unless ignore_ci_component
fake_job = <<~YAML
.ignore:
script: echo ok
YAML
file.end_with?('.yml') && %r{^\s*- component:.*CI_SERVER_}.match?(content) ? fake_job : content
end
let_it_be(:group) { create(:group, path: 'ci-org') }
let_it_be(:user) { create(:user) }
@ -15,11 +69,13 @@ RSpec.describe 'ci jobs dependency', feature_category: :tooling,
let(:gitlab_com_variables_attributes_base) do
[
{ key: 'CI_SERVER_HOST', value: 'gitlab.com' },
{ key: 'CI_PROJECT_NAMESPACE', value: 'gitlab-org/gitlab' }
{ key: 'CI_PROJECT_NAMESPACE', value: 'gitlab-org' },
{ key: 'CI_PROJECT_PATH', value: 'gitlab-org/gitlab' }
]
end
let(:create_pipeline_service) { Ci::CreatePipelineService.new(project, user, ref: master_branch) }
let(:jobs) { pipeline.stages.flat_map { |s| s.statuses.map(&:name) } }
around(:all) do |example|
with_net_connect_allowed { example.run } # creating pipeline requires network call to fetch templates
@ -36,38 +92,44 @@ RSpec.describe 'ci jobs dependency', feature_category: :tooling,
)
end
context 'with gitlab.com gitlab-org/gitlab master pipeline' do
shared_examples 'master pipeline' do
let(:content) do
project.repository.blob_at(master_branch, '.gitlab-ci.yml').data
end
shared_examples 'master pipeline' do |trigger_source|
subject(:pipeline) do
create_pipeline_service
.execute(trigger_source, dry_run: true, content: content, variables_attributes: variables_attributes)
.payload
end
it 'is valid' do
expect(pipeline.yaml_errors).to be nil
expect(pipeline.status).to eq('created')
end
subject(:pipeline) do
create_pipeline_service
.execute(trigger_source, dry_run: true, content: content, variables_attributes: variables_attributes)
.payload
end
it 'is valid' do
expect(pipeline.yaml_errors).to be nil
expect(pipeline.status).to eq('created')
expect(jobs).to include(expected_job_name)
end
end
context 'with gitlab.com gitlab-org/gitlab master pipeline' do
context 'with default master pipeline' do
let(:variables_attributes) { gitlab_com_variables_attributes_base }
let(:trigger_source) { :push }
let(:expected_job_name) { 'rspec background_migration pg14 1/5' }
# Test: remove rules from .rails:rules:setup-test-env
it_behaves_like 'master pipeline', :push
it_behaves_like 'master pipeline'
end
context 'with scheduled nightly' do
let(:trigger_source) { :schedule }
let(:expected_job_name) { 'rspec migration pg16 1/15' }
let(:variables_attributes) do
[
*gitlab_com_variables_attributes_base,
{ key: 'SCHEDULE_TYPE', value: 'nightly' }
]
end
# .if-default-branch-schedule-nightly
# included in .qa:rules:package-and-test-ce
# used by e2e:package-and-test-ce
@ -77,10 +139,12 @@ RSpec.describe 'ci jobs dependency', feature_category: :tooling,
# Test: I can remove this rule from .qa:rules:determine-e2e-tests
# - <<: *if-dot-com-gitlab-org-schedule
# allow_failure: true
it_behaves_like 'master pipeline', :schedule
it_behaves_like 'master pipeline'
end
context 'with scheduled maintenance' do
let(:trigger_source) { :schedule }
let(:expected_job_name) { 'rspec-ee system pg14 no_gitaly_transactions 1/14' }
let(:variables_attributes) do
[
*gitlab_com_variables_attributes_base,
@ -88,7 +152,33 @@ RSpec.describe 'ci jobs dependency', feature_category: :tooling,
]
end
it_behaves_like 'master pipeline', :schedule
it_behaves_like 'master pipeline'
end
end
context 'with gitlab.com gitlab-org gitlab-foss project' do
let(:variables_attributes) do
[
{ key: 'CI_SERVER_HOST', value: 'gitlab.com' },
{ key: 'CI_PROJECT_NAMESPACE', value: 'gitlab-org' },
{ key: 'CI_PROJECT_PATH', value: 'gitlab-org/gitlab-foss' }
]
end
context 'with master pipeline triggered by push' do
let(:trigger_source) { :push }
let(:expected_job_name) { 'rspec background_migration pg14 1/5' }
it_behaves_like 'master pipeline'
end
context 'with scheduled master pipeline' do
let(:trigger_source) { :schedule }
let(:expected_job_name) { 'rspec background_migration pg14 1/5' }
# Verify by removing the following rule from .qa:rules:e2e:test-on-cng
# - !reference [".qa:rules:package-and-test-never-run", rules]
it_behaves_like 'master pipeline'
end
end
@ -149,7 +239,6 @@ RSpec.describe 'ci jobs dependency', feature_category: :tooling,
end
it "creates a valid pipeline with expected job" do
jobs = pipeline.stages.flat_map { |s| s.statuses.map(&:name) }.join("\n")
expect(pipeline.yaml_errors).to be nil
expect(pipeline.status).to eq('created')
# to confirm that the dependent job is actually created and rule out false positives
@ -166,13 +255,13 @@ RSpec.describe 'ci jobs dependency', feature_category: :tooling,
it_behaves_like 'merge request pipeline'
end
# backstage-patterns, #.code-backstage-patterns and frontend ci pattern
# Test: remove the following rules from `.frontend:rules:default-frontend-jobs`:
# - <<: *if-merge-request-labels-run-all-rspec
# - <<: *if-default-refs
# changes: *code-backstage-patterns
context 'when unlabled MR is changing Dangerfile, .gitlab/ci/frontend.gitlab-ci.yml' do
let(:labels_string) { '' }
let(:changed_files) { ['Dangerfile', '.gitlab/ci/frontend.gitlab-ci.yml'] }
let(:expected_job_name) { 'rspec-all frontend_fixture' }
let(:expected_job_name) { 'rspec-all frontend_fixture 1/7' }
it_behaves_like 'merge request pipeline'
end
@ -182,7 +271,7 @@ RSpec.describe 'ci jobs dependency', feature_category: :tooling,
context 'when MR labeled with `pipeline:run-all-rspec` is changing keeps/quarantine-test.rb' do
let(:labels_string) { 'pipeline:run-all-rspec' }
let(:changed_files) { ['keeps/quarantine-test.rb'] }
let(:expected_job_name) { 'rspec-all frontend_fixture' }
let(:expected_job_name) { 'rspec-all frontend_fixture 1/7' }
it_behaves_like 'merge request pipeline'
end
@ -208,7 +297,7 @@ RSpec.describe 'ci jobs dependency', feature_category: :tooling,
let(:create_pipeline_service) { Ci::CreatePipelineService.new(project, user, ref: target_branch) }
let(:labels_string) { '' }
let(:changed_files) { ['keeps/quarantine-test.rb'] }
let(:expected_job_name) { 'rspec-all frontend_fixture' }
let(:expected_job_name) { 'rspec-all frontend_fixture 1/7' }
before do
sync_local_files_to_project(

View File

@ -1,3 +1,4 @@
import { builders } from 'prosemirror-test-builder';
import { GlLoadingIcon, GlListboxItem, GlCollapsibleListbox } from '@gitlab/ui';
import { nextTick } from 'vue';
import { mountExtended } from 'helpers/vue_test_utils_helper';
@ -6,7 +7,7 @@ import ReferenceBubbleMenu from '~/content_editor/components/bubble_menus/refere
import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue';
import { stubComponent } from 'helpers/stub_component';
import Reference from '~/content_editor/extensions/reference';
import { createTestEditor, emitEditorEvent, createDocBuilder } from '../../test_utils';
import { createTestEditor, emitEditorEvent } from '../../test_utils';
const mockWorkItem = {
href: 'https://gitlab.com/gitlab-org/gitlab/-/work_items/12',
@ -51,14 +52,7 @@ describe('content_editor/components/bubble_menus/reference_bubble_menu', () => {
contentEditor = { resolveReference: jest.fn().mockImplementation(() => new Promise(() => {})) };
eventHub = eventHubFactory();
({
builders: { doc, p, reference },
} = createDocBuilder({
tiptapEditor,
names: {
reference: { nodeType: Reference.name },
},
}));
({ doc, paragraph: p, reference } = builders(tiptapEditor.schema));
};
const expectedDocs = {

View File

@ -1,3 +1,4 @@
import { builders } from 'prosemirror-test-builder';
import { nextTick } from 'vue';
import { NodeViewWrapper } from '@tiptap/vue-2';
import { mountExtended } from 'helpers/vue_test_utils_helper';
@ -6,7 +7,7 @@ import eventHubFactory from '~/helpers/event_hub_factory';
import Heading from '~/content_editor/extensions/heading';
import Diagram from '~/content_editor/extensions/diagram';
import TableOfContentsWrapper from '~/content_editor/components/wrappers/table_of_contents.vue';
import { createTestEditor, createDocBuilder, emitEditorEvent } from '../../test_utils';
import { createTestEditor, emitEditorEvent } from '../../test_utils';
describe('content/components/wrappers/table_of_contents', () => {
let wrapper;
@ -43,14 +44,7 @@ describe('content/components/wrappers/table_of_contents', () => {
buildEditor();
createWrapper();
const {
builders: { heading, doc },
} = createDocBuilder({
tiptapEditor,
names: {
heading: { nodeType: Heading.name },
},
});
const { heading, doc } = builders(tiptapEditor.schema);
const initialDoc = doc(
heading({ level: 1 }, 'Heading 1'),

View File

@ -1,6 +1,7 @@
import fs from 'fs';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { builders } from 'prosemirror-test-builder';
import Attachment from '~/content_editor/extensions/attachment';
import DrawioDiagram from '~/content_editor/extensions/drawio_diagram';
import Image from '~/content_editor/extensions/image';
@ -10,7 +11,7 @@ import Link from '~/content_editor/extensions/link';
import { VARIANT_DANGER } from '~/alert';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import eventHubFactory from '~/helpers/event_hub_factory';
import { createTestEditor, createDocBuilder, expectDocumentAfterTransaction } from '../test_utils';
import { createTestEditor, expectDocumentAfterTransaction } from '../test_utils';
import {
PROJECT_WIKI_ATTACHMENT_IMAGE_HTML,
PROJECT_WIKI_ATTACHMENT_IMAGE_SVG_HTML,
@ -81,17 +82,14 @@ describe('content_editor/extensions/attachment', () => {
});
({
builders: { doc, p, image, audio, video, link, drawioDiagram },
} = createDocBuilder({
tiptapEditor,
names: {
image: { nodeType: Image.name },
link: { nodeType: Link.name },
audio: { nodeType: Audio.name },
video: { nodeType: Video.name },
drawioDiagram: { nodeType: DrawioDiagram.name },
},
}));
doc,
paragraph: p,
image,
audio,
video,
link,
drawioDiagram,
} = builders(tiptapEditor.schema));
mock = new MockAdapter(axios);
});

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import Blockquote from '~/content_editor/extensions/blockquote';
import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils';
import { createTestEditor, triggerNodeInputRule } from '../test_utils';
describe('content_editor/extensions/blockquote', () => {
let tiptapEditor;
@ -10,14 +11,7 @@ describe('content_editor/extensions/blockquote', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [Blockquote] });
({
builders: { doc, p, blockquote },
} = createDocBuilder({
tiptapEditor,
names: {
blockquote: { nodeType: Blockquote.name },
},
}));
({ doc, paragraph: p, blockquote } = builders(tiptapEditor.schema));
});
it.each`

View File

@ -1,6 +1,7 @@
import { builders } from 'prosemirror-test-builder';
import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
import languageLoader from '~/content_editor/services/code_block_language_loader';
import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils';
import { createTestEditor, triggerNodeInputRule } from '../test_utils';
const CODE_BLOCK_HTML = `<div class="gl-relative markdown-code-block js-markdown-code">&#x000A;<pre data-sourcepos="1:1-3:3" data-canonical-lang="javascript" class="code highlight js-syntax-highlight language-javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello world</span><span class="dl">'</span><span class="p">)</span></span></code></pre>&#x000A;<copy-code></copy-code>&#x000A;</div>`;
@ -16,14 +17,7 @@ describe('content_editor/extensions/code_block_highlight', () => {
extensions: [CodeBlockHighlight],
});
({
builders: { doc, codeBlock },
} = createDocBuilder({
tiptapEditor,
names: {
codeBlock: { nodeType: CodeBlockHighlight.name },
},
}));
({ doc, codeBlock } = builders(tiptapEditor.schema));
});
describe('when parsing HTML', () => {

View File

@ -1,6 +1,7 @@
import { builders } from 'prosemirror-test-builder';
import Bold from '~/content_editor/extensions/bold';
import Code from '~/content_editor/extensions/code';
import { createTestEditor, createDocBuilder } from '../test_utils';
import { createTestEditor } from '../test_utils';
describe('content_editor/extensions/code', () => {
let tiptapEditor;
@ -12,15 +13,7 @@ describe('content_editor/extensions/code', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [Bold, Code] });
({
builders: { doc, p, bold, code },
} = createDocBuilder({
tiptapEditor,
names: {
bold: { markType: Bold.name },
code: { markType: Code.name },
},
}));
({ doc, paragraph: p, bold, code } = builders(tiptapEditor.schema));
});
it.each`

View File

@ -1,8 +1,8 @@
import { builders } from 'prosemirror-test-builder';
import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
import CodeSuggestion from '~/content_editor/extensions/code_suggestion';
import {
createTestEditor,
createDocBuilder,
triggerNodeInputRule,
expectDocumentAfterTransaction,
sleep,
@ -51,15 +51,7 @@ describe('content_editor/extensions/code_suggestion', () => {
],
});
({
builders: { doc, codeSuggestion },
} = createDocBuilder({
tiptapEditor,
names: {
codeBlock: { nodeType: CodeBlockHighlight.name },
codeSuggestion: { nodeType: CodeSuggestion.name },
},
}));
({ doc, codeSuggestion } = builders(tiptapEditor.schema));
};
describe('insertCodeSuggestion command', () => {

View File

@ -1,3 +1,4 @@
import { builders } from 'prosemirror-test-builder';
import CopyPaste from '~/content_editor/extensions/copy_paste';
import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
import Loading, { findAllLoaders } from '~/content_editor/extensions/loading';
@ -18,7 +19,7 @@ import eventHubFactory from '~/helpers/event_hub_factory';
import { ALERT_EVENT } from '~/content_editor/constants';
import waitForPromises from 'helpers/wait_for_promises';
import MarkdownSerializer from '~/content_editor/services/markdown_serializer';
import { createTestEditor, createDocBuilder, waitUntilNextDocTransaction } from '../test_utils';
import { createTestEditor, waitUntilNextDocTransaction } from '../test_utils';
const PARAGRAPH_HTML =
'<p dir="auto">Some text with <strong>bold</strong> and <em>italic</em> text.</p>';
@ -72,20 +73,15 @@ describe('content_editor/extensions/copy_paste', () => {
});
({
builders: { doc, p, bold, italic, heading, codeBlock, bulletList, listItem },
} = createDocBuilder({
tiptapEditor,
names: {
bold: { markType: Bold.name },
italic: { markType: Italic.name },
heading: { nodeType: Heading.name },
bulletList: { nodeType: BulletList.name },
listItem: { nodeType: ListItem.name },
codeBlock: { nodeType: CodeBlockHighlight.name },
diagram: { nodeType: Diagram.name },
frontmatter: { nodeType: Frontmatter.name },
},
}));
doc,
paragraph: p,
bold,
italic,
heading,
codeBlock,
bulletList,
listItem,
} = builders(tiptapEditor.schema));
});
const buildClipboardEvent = ({ eventName = 'paste', data = {}, types = ['text/plain'] } = {}) => {

View File

@ -1,6 +1,7 @@
import { builders } from 'prosemirror-test-builder';
import DescriptionList from '~/content_editor/extensions/description_list';
import DescriptionItem from '~/content_editor/extensions/description_item';
import { createTestEditor, createDocBuilder, triggerKeyboardInput } from '../test_utils';
import { createTestEditor, triggerKeyboardInput } from '../test_utils';
describe('content_editor/extensions/description_item', () => {
let tiptapEditor;
@ -12,15 +13,7 @@ describe('content_editor/extensions/description_item', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [DescriptionList, DescriptionItem] });
({
builders: { doc, p, descriptionList, descriptionItem },
} = createDocBuilder({
tiptapEditor,
names: {
descriptionList: { nodeType: DescriptionList.name },
descriptionItem: { nodeType: DescriptionItem.name },
},
}));
({ doc, paragraph: p, descriptionList, descriptionItem } = builders(tiptapEditor.schema));
});
describe('shortcut: Enter', () => {

View File

@ -1,6 +1,7 @@
import { builders } from 'prosemirror-test-builder';
import DescriptionList from '~/content_editor/extensions/description_list';
import DescriptionItem from '~/content_editor/extensions/description_item';
import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils';
import { createTestEditor, triggerNodeInputRule } from '../test_utils';
describe('content_editor/extensions/description_list', () => {
let tiptapEditor;
@ -12,15 +13,7 @@ describe('content_editor/extensions/description_list', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [DescriptionList, DescriptionItem] });
({
builders: { doc, p, descriptionList, descriptionItem },
} = createDocBuilder({
tiptapEditor,
names: {
descriptionList: { nodeType: DescriptionList.name },
descriptionItem: { nodeType: DescriptionItem.name },
},
}));
({ doc, paragraph: p, descriptionList, descriptionItem } = builders(tiptapEditor.schema));
});
it.each`

View File

@ -1,6 +1,7 @@
import { builders } from 'prosemirror-test-builder';
import Details from '~/content_editor/extensions/details';
import DetailsContent from '~/content_editor/extensions/details_content';
import { createTestEditor, createDocBuilder, triggerKeyboardInput } from '../test_utils';
import { createTestEditor, triggerKeyboardInput } from '../test_utils';
describe('content_editor/extensions/details_content', () => {
let tiptapEditor;
@ -12,15 +13,7 @@ describe('content_editor/extensions/details_content', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [Details, DetailsContent] });
({
builders: { doc, p, details, detailsContent },
} = createDocBuilder({
tiptapEditor,
names: {
details: { nodeType: Details.name },
detailsContent: { nodeType: DetailsContent.name },
},
}));
({ doc, paragraph: p, details, detailsContent } = builders(tiptapEditor.schema));
});
describe('shortcut: Enter', () => {

View File

@ -1,6 +1,7 @@
import { builders } from 'prosemirror-test-builder';
import Details from '~/content_editor/extensions/details';
import DetailsContent from '~/content_editor/extensions/details_content';
import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils';
import { createTestEditor, triggerNodeInputRule } from '../test_utils';
describe('content_editor/extensions/details', () => {
let tiptapEditor;
@ -12,15 +13,7 @@ describe('content_editor/extensions/details', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [Details, DetailsContent] });
({
builders: { doc, p, details, detailsContent },
} = createDocBuilder({
tiptapEditor,
names: {
details: { nodeType: Details.name },
detailsContent: { nodeType: DetailsContent.name },
},
}));
({ doc, paragraph: p, details, detailsContent } = builders(tiptapEditor.schema));
});
describe('setDetails command', () => {

View File

@ -1,6 +1,7 @@
import { builders } from 'prosemirror-test-builder';
import Diagram from '~/content_editor/extensions/diagram';
import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
import { createTestEditor, createDocBuilder } from '../test_utils';
import { createTestEditor } from '../test_utils';
const DIAGRAM_HTML = `<div class="gl-relative markdown-code-block js-markdown-code">&#x000A;<pre data-sourcepos="1:1-5:3" data-canonical-lang="mermaid" class="code highlight js-syntax-highlight language-mermaid" v-pre="true"><code class="js-render-mermaid"><span id="LC1" class="line" lang="mermaid">pie title NETFLIX</span>&#x000A;<span id="LC2" class="line" lang="mermaid"> "Time spent looking for movie" : 90</span>&#x000A;<span id="LC3" class="line" lang="mermaid"> "Time spent watching it" : 10</span></code></pre>&#x000A;<copy-code></copy-code>&#x000A;</div>`;
@ -14,15 +15,7 @@ describe('content_editor/extensions/diagram', () => {
extensions: [CodeBlockHighlight, Diagram],
});
({
builders: { doc, diagram },
} = createDocBuilder({
tiptapEditor,
names: {
codeBlock: { nodeType: CodeBlockHighlight.name },
diagram: { nodeType: Diagram.name },
},
}));
({ doc, diagram } = builders(tiptapEditor.schema));
};
it('inherits from code block highlight extension', () => {

View File

@ -1,8 +1,9 @@
import { builders } from 'prosemirror-test-builder';
import DrawioDiagram from '~/content_editor/extensions/drawio_diagram';
import Image from '~/content_editor/extensions/image';
import { create } from '~/drawio/content_editor_facade';
import { launchDrawioEditor } from '~/drawio/drawio_editor';
import { createTestEditor, createDocBuilder } from '../test_utils';
import { createTestEditor } from '../test_utils';
import {
PROJECT_WIKI_ATTACHMENT_IMAGE_HTML,
PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML,
@ -15,7 +16,7 @@ jest.mock('~/drawio/drawio_editor');
describe('content_editor/extensions/drawio_diagram', () => {
let tiptapEditor;
let doc;
let paragraph;
let p;
let image;
let drawioDiagram;
let assetResolver;
@ -28,24 +29,14 @@ describe('content_editor/extensions/drawio_diagram', () => {
tiptapEditor = createTestEditor({
extensions: [Image, DrawioDiagram.configure({ uploadsPath, assetResolver })],
});
const { builders } = createDocBuilder({
tiptapEditor,
names: {
image: { nodeType: Image.name },
drawioDiagram: { nodeType: DrawioDiagram.name },
},
});
doc = builders.doc;
paragraph = builders.paragraph;
image = builders.image;
drawioDiagram = builders.drawioDiagram;
({ doc, paragraph: p, image, drawioDiagram } = builders(tiptapEditor.schema));
});
describe('parsing', () => {
it('distinguishes a drawio diagram from an image', () => {
const expectedDocWithDiagram = doc(
paragraph(
p(
drawioDiagram({
alt: 'test-file',
canonicalSrc: 'test-file.drawio.svg',
@ -54,7 +45,7 @@ describe('content_editor/extensions/drawio_diagram', () => {
),
);
const expectedDocWithImage = doc(
paragraph(
p(
image({
alt: 'test-file',
canonicalSrc: 'test-file.png',

View File

@ -1,13 +1,13 @@
import { builders, eq } from 'prosemirror-test-builder';
import { initEmojiMock } from 'helpers/emoji';
import Emoji from '~/content_editor/extensions/emoji';
import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils';
import { createTestEditor, triggerNodeInputRule } from '../test_utils';
describe('content_editor/extensions/emoji', () => {
let tiptapEditor;
let doc;
let p;
let emoji;
let eq;
beforeEach(async () => {
await initEmojiMock();
@ -15,15 +15,7 @@ describe('content_editor/extensions/emoji', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [Emoji] });
({
builders: { doc, p, emoji },
eq,
} = createDocBuilder({
tiptapEditor,
names: {
loading: { nodeType: Emoji.name },
},
}));
({ doc, paragraph: p, emoji } = builders(tiptapEditor.schema));
});
describe('when typing a valid emoji input rule', () => {

View File

@ -1,6 +1,7 @@
import { builders } from 'prosemirror-test-builder';
import Frontmatter from '~/content_editor/extensions/frontmatter';
import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils';
import { createTestEditor, triggerNodeInputRule } from '../test_utils';
describe('content_editor/extensions/frontmatter', () => {
let tiptapEditor;
@ -11,15 +12,7 @@ describe('content_editor/extensions/frontmatter', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [Frontmatter, CodeBlockHighlight] });
({
builders: { doc, codeBlock, frontmatter },
} = createDocBuilder({
tiptapEditor,
names: {
frontmatter: { nodeType: Frontmatter.name },
codeBlock: { nodeType: CodeBlockHighlight.name },
},
}));
({ doc, codeBlock, frontmatter } = builders(tiptapEditor.schema));
});
it('inherits from code block highlight extension', () => {

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import HardBreak from '~/content_editor/extensions/hard_break';
import { createTestEditor, createDocBuilder } from '../test_utils';
import { createTestEditor } from '../test_utils';
describe('content_editor/extensions/hard_break', () => {
let tiptapEditor;
@ -10,12 +11,7 @@ describe('content_editor/extensions/hard_break', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [HardBreak] });
({
builders: { doc, p },
} = createDocBuilder({
tiptapEditor,
names: { hardBreak: { nodeType: HardBreak.name } },
}));
({ doc, paragraph: p } = builders(tiptapEditor.schema));
});
describe('Mod-Enter shortcut', () => {

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import Heading from '~/content_editor/extensions/heading';
import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils';
import { createTestEditor, triggerNodeInputRule } from '../test_utils';
describe('content_editor/extensions/heading', () => {
let tiptapEditor;
@ -9,14 +10,7 @@ describe('content_editor/extensions/heading', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [Heading] });
({
builders: { doc, p, heading },
} = createDocBuilder({
tiptapEditor,
names: {
heading: { nodeType: Heading.name },
},
}));
({ doc, paragraph: p, heading } = builders(tiptapEditor.schema));
});
describe('when typing a valid heading input rule', () => {

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import HorizontalRule from '~/content_editor/extensions/horizontal_rule';
import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils';
import { createTestEditor, triggerNodeInputRule } from '../test_utils';
describe('content_editor/extensions/horizontal_rule', () => {
let tiptapEditor;
@ -10,14 +11,7 @@ describe('content_editor/extensions/horizontal_rule', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [HorizontalRule] });
({
builders: { doc, p, horizontalRule },
} = createDocBuilder({
tiptapEditor,
names: {
horizontalRule: { nodeType: HorizontalRule.name },
},
}));
({ doc, paragraph: p, horizontalRule } = builders(tiptapEditor.schema));
});
it.each`

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import HTMLMarks from '~/content_editor/extensions/html_marks';
import { createTestEditor, createDocBuilder } from '../test_utils';
import { createTestEditor } from '../test_utils';
describe('content_editor/extensions/html_marks', () => {
let tiptapEditor;
@ -25,37 +26,24 @@ describe('content_editor/extensions/html_marks', () => {
tiptapEditor = createTestEditor({ extensions: [...HTMLMarks] });
({
builders: {
doc,
ins,
abbr,
bdo,
cite,
dfn,
small,
span,
time,
kbd,
q,
samp,
var: varMark,
ruby,
rp,
rt,
p,
},
} = createDocBuilder({
tiptapEditor,
names: {
...HTMLMarks.reduce(
(builders, htmlMark) => ({
...builders,
[htmlMark.name]: { markType: htmlMark.name },
}),
{},
),
},
}));
doc,
ins,
abbr,
bdo,
cite,
dfn,
small,
span,
time,
kbd,
q,
samp,
var: varMark,
ruby,
rp,
rt,
paragraph: p,
} = builders(tiptapEditor.schema));
});
it.each`

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import HTMLNodes from '~/content_editor/extensions/html_nodes';
import { createTestEditor, createDocBuilder } from '../test_utils';
import { createTestEditor } from '../test_utils';
describe('content_editor/extensions/html_nodes', () => {
let tiptapEditor;
@ -11,20 +12,7 @@ describe('content_editor/extensions/html_nodes', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [...HTMLNodes] });
({
builders: { doc, p, pre, div },
} = createDocBuilder({
tiptapEditor,
names: {
...HTMLNodes.reduce(
(builders, htmlNode) => ({
...builders,
[htmlNode.name]: { nodeType: htmlNode.name },
}),
{},
),
},
}));
({ doc, paragraph: p, pre, div } = builders(tiptapEditor.schema));
});
it.each`

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import Image from '~/content_editor/extensions/image';
import { createTestEditor, createDocBuilder } from '../test_utils';
import { createTestEditor } from '../test_utils';
describe('content_editor/extensions/image', () => {
let tiptapEditor;
@ -10,14 +11,7 @@ describe('content_editor/extensions/image', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [Image] });
({
builders: { doc, p, image },
} = createDocBuilder({
tiptapEditor,
names: {
image: { nodeType: Image.name },
},
}));
({ doc, paragraph: p, image } = builders(tiptapEditor.schema));
});
it('sets the draggable option to true', () => {

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import InlineDiff from '~/content_editor/extensions/inline_diff';
import { createTestEditor, createDocBuilder, triggerMarkInputRule } from '../test_utils';
import { createTestEditor, triggerMarkInputRule } from '../test_utils';
describe('content_editor/extensions/inline_diff', () => {
let tiptapEditor;
@ -9,14 +10,7 @@ describe('content_editor/extensions/inline_diff', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [InlineDiff] });
({
builders: { doc, p, inlineDiff },
} = createDocBuilder({
tiptapEditor,
names: {
inlineDiff: { markType: InlineDiff.name },
},
}));
({ doc, paragraph: p, inlineDiff } = builders(tiptapEditor.schema));
});
it.each`

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import Link from '~/content_editor/extensions/link';
import { createTestEditor, createDocBuilder, triggerMarkInputRule } from '../test_utils';
import { createTestEditor, triggerMarkInputRule } from '../test_utils';
describe('content_editor/extensions/link', () => {
let tiptapEditor;
@ -9,14 +10,7 @@ describe('content_editor/extensions/link', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [Link] });
({
builders: { doc, p, link },
} = createDocBuilder({
tiptapEditor,
names: {
link: { markType: Link.name },
},
}));
({ doc, paragraph: p, link } = builders(tiptapEditor.schema));
});
afterEach(() => {

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import MathInline from '~/content_editor/extensions/math_inline';
import { createTestEditor, createDocBuilder, triggerMarkInputRule } from '../test_utils';
import { createTestEditor, triggerMarkInputRule } from '../test_utils';
describe('content_editor/extensions/math_inline', () => {
let tiptapEditor;
@ -10,14 +11,7 @@ describe('content_editor/extensions/math_inline', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [MathInline] });
({
builders: { doc, p, mathInline },
} = createDocBuilder({
tiptapEditor,
names: {
details: { markType: MathInline.name },
},
}));
({ doc, paragraph: p, mathInline } = builders(tiptapEditor.schema));
});
it.each`

View File

@ -1,4 +1,5 @@
import { createTestEditor, createDocBuilder } from '../test_utils';
import { builders } from 'prosemirror-test-builder';
import { createTestEditor } from '../test_utils';
describe('content_editor/extensions/paragraph', () => {
let tiptapEditor;
@ -8,9 +9,7 @@ describe('content_editor/extensions/paragraph', () => {
beforeEach(() => {
tiptapEditor = createTestEditor();
({
builders: { doc, p },
} = createDocBuilder({ tiptapEditor }));
({ doc, paragraph: p } = builders(tiptapEditor.schema));
});
describe('Shift-Enter shortcut', () => {

View File

@ -1,3 +1,4 @@
import { builders } from 'prosemirror-test-builder';
import Reference from '~/content_editor/extensions/reference';
import ReferenceLabel from '~/content_editor/extensions/reference_label';
import AssetResolver from '~/content_editor/services/asset_resolver';
@ -11,12 +12,7 @@ import {
RESOLVED_USER_HTML,
RESOLVED_VULNERABILITY_HTML,
} from '../test_constants';
import {
createTestEditor,
createDocBuilder,
triggerNodeInputRule,
waitUntilTransaction,
} from '../test_utils';
import { createTestEditor, triggerNodeInputRule, waitUntilTransaction } from '../test_utils';
describe('content_editor/extensions/reference', () => {
let tiptapEditor;
@ -35,15 +31,7 @@ describe('content_editor/extensions/reference', () => {
extensions: [Reference.configure({ assetResolver }), ReferenceLabel],
});
({
builders: { doc, p, reference, referenceLabel },
} = createDocBuilder({
tiptapEditor,
names: {
reference: { nodeType: Reference.name },
referenceLabel: { nodeType: ReferenceLabel.name },
},
}));
({ doc, paragraph: p, reference, referenceLabel } = builders(tiptapEditor.schema));
});
describe('when typing a valid reference input rule', () => {

View File

@ -1,5 +1,6 @@
import { builders } from 'prosemirror-test-builder';
import TableOfContents from '~/content_editor/extensions/table_of_contents';
import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils';
import { createTestEditor, triggerNodeInputRule } from '../test_utils';
describe('content_editor/extensions/table_of_contents', () => {
let tiptapEditor;
@ -9,12 +10,7 @@ describe('content_editor/extensions/table_of_contents', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [TableOfContents] });
({
builders: { doc, p, tableOfContents },
} = createDocBuilder({
tiptapEditor,
names: { tableOfContents: { nodeType: TableOfContents.name } },
}));
({ doc, paragraph: p, tableOfContents } = builders(tiptapEditor.schema));
});
it.each`

View File

@ -1,3 +1,4 @@
import { builders } from 'prosemirror-test-builder';
import Bold from '~/content_editor/extensions/bold';
import BulletList from '~/content_editor/extensions/bullet_list';
import ListItem from '~/content_editor/extensions/list_item';
@ -5,7 +6,7 @@ import Table from '~/content_editor/extensions/table';
import TableCell from '~/content_editor/extensions/table_cell';
import TableRow from '~/content_editor/extensions/table_row';
import TableHeader from '~/content_editor/extensions/table_header';
import { createTestEditor, createDocBuilder } from '../test_utils';
import { createTestEditor } from '../test_utils';
describe('content_editor/extensions/table', () => {
let tiptapEditor;
@ -24,19 +25,13 @@ describe('content_editor/extensions/table', () => {
});
({
builders: { doc, p, table, tableCell, tableHeader, tableRow },
} = createDocBuilder({
tiptapEditor,
names: {
bold: { markType: Bold.name },
table: { nodeType: Table.name },
tableHeader: { nodeType: TableHeader.name },
tableCell: { nodeType: TableCell.name },
tableRow: { nodeType: TableRow.name },
bulletList: { nodeType: BulletList.name },
listItem: { nodeType: ListItem.name },
},
}));
doc,
paragraph: p,
table,
tableCell,
tableHeader,
tableRow,
} = builders(tiptapEditor.schema));
initialDoc = doc(
table(

View File

@ -1,6 +1,7 @@
import { builders } from 'prosemirror-test-builder';
import TaskList from '~/content_editor/extensions/task_list';
import TaskItem from '~/content_editor/extensions/task_item';
import { createTestEditor, createDocBuilder } from '../test_utils';
import { createTestEditor } from '../test_utils';
describe('content_editor/extensions/task_item', () => {
let tiptapEditor;
@ -12,15 +13,7 @@ describe('content_editor/extensions/task_item', () => {
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [TaskList, TaskItem] });
({
builders: { doc, p, taskList, taskItem },
} = createDocBuilder({
tiptapEditor,
names: {
taskItem: { nodeType: TaskItem.name },
taskList: { nodeType: TaskList.name },
},
}));
({ doc, paragraph: p, taskList, taskItem } = builders(tiptapEditor.schema));
});
it('sets the draggable option to true', () => {

Some files were not shown because too many files have changed in this diff Show More