Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
3669bcfaaa
commit
0e6368a09e
|
|
@ -7,6 +7,11 @@ module Resolvers
|
|||
|
||||
type Types::Notes::NoteType.connection_type, null: false
|
||||
|
||||
argument :filter, Types::WorkItems::NotesFilterTypeEnum,
|
||||
required: false,
|
||||
default_value: ::UserPreference::NOTES_FILTERS[:all_notes],
|
||||
description: 'Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY.'
|
||||
|
||||
before_connection_authorization do |nodes, current_user|
|
||||
next if nodes.blank?
|
||||
|
||||
|
|
@ -16,8 +21,9 @@ module Resolvers
|
|||
::Preloaders::Projects::NotesPreloader.new(project, current_user).call(nodes)
|
||||
end
|
||||
|
||||
def resolve_with_lookahead(*)
|
||||
apply_lookahead(object.notes.fresh)
|
||||
def resolve_with_lookahead(**args)
|
||||
notes = NotesFinder.new(current_user, build_params(args)).execute
|
||||
apply_lookahead(notes)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -31,6 +37,17 @@ module Resolvers
|
|||
award_emoji: [:award_emoji]
|
||||
}
|
||||
end
|
||||
|
||||
def build_params(args)
|
||||
params = {
|
||||
project: object.project,
|
||||
target: object
|
||||
}
|
||||
|
||||
params[:notes_filter] = args[:filter] if args[:filter].present?
|
||||
|
||||
params
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ module GroupsHelper
|
|||
}
|
||||
end
|
||||
|
||||
def enabled_git_access_protocol_options_for_group
|
||||
def enabled_git_access_protocol_options_for_group(_)
|
||||
case ::Gitlab::CurrentSettings.enabled_git_access_protocol
|
||||
when nil, ""
|
||||
[[_("Both SSH and HTTP(S)"), "all"], [_("Only SSH"), "ssh"], [_("Only HTTP(S)"), "http"]]
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
|
|||
if: :auto_devops_enabled?
|
||||
|
||||
validates :enabled_git_access_protocol,
|
||||
inclusion: { in: %w[ssh http], allow_blank: true }
|
||||
inclusion: { in: ->(_) { enabled_git_access_protocol_values }, allow_blank: true }
|
||||
|
||||
validates :domain_denylist,
|
||||
presence: { message: 'Domain denylist cannot be empty if denylist is enabled.' },
|
||||
|
|
@ -959,6 +959,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
|
|||
HUMANIZED_ATTRIBUTES[attribute.to_sym] || super
|
||||
end
|
||||
|
||||
def self.enabled_git_access_protocol_values
|
||||
%w[ssh http]
|
||||
end
|
||||
|
||||
def parsed_grafana_url
|
||||
@parsed_grafana_url ||= Gitlab::Utils.parse_url(grafana_url)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ class Group < Namespace
|
|||
return GroupMember::NO_ACCESS unless user
|
||||
return GroupMember::OWNER if user.can_admin_all_resources? && !only_concrete_membership
|
||||
|
||||
max_member_access([user.id])[user.id]
|
||||
max_member_access(user)
|
||||
end
|
||||
|
||||
def mattermost_team_params
|
||||
|
|
@ -953,16 +953,16 @@ class Group < Namespace
|
|||
end
|
||||
end
|
||||
|
||||
def max_member_access(user_ids)
|
||||
::Gitlab::Database.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417455") do
|
||||
Gitlab::SafeRequestLoader.execute(
|
||||
resource_key: max_member_access_for_resource_key(User),
|
||||
resource_ids: user_ids,
|
||||
default_value: Gitlab::Access::NO_ACCESS
|
||||
) do |user_ids|
|
||||
members_with_parents.where(user_id: user_ids).group(:user_id).maximum(:access_level)
|
||||
end
|
||||
end
|
||||
def max_member_access(user)
|
||||
Gitlab::SafeRequestLoader.execute(
|
||||
resource_key: max_member_access_for_resource_key(User),
|
||||
resource_ids: [user.id],
|
||||
default_value: Gitlab::Access::NO_ACCESS
|
||||
) do |_|
|
||||
next {} unless user.active?
|
||||
|
||||
members_with_parents(only_active_users: false).where(user_id: user.id).group(:user_id).maximum(:access_level)
|
||||
end.fetch(user.id)
|
||||
end
|
||||
|
||||
def update_two_factor_requirement
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class NamespaceSetting < ApplicationRecord
|
|||
belongs_to :namespace, inverse_of: :namespace_settings
|
||||
|
||||
enum jobs_to_be_done: { basics: 0, move_repository: 1, code_storage: 2, exploring: 3, ci: 4, other: 5 }, _suffix: true
|
||||
enum enabled_git_access_protocol: { all: 0, ssh: 1, http: 2 }, _suffix: true
|
||||
enum enabled_git_access_protocol: { all: 0, ssh: 1, http: 2, ssh_certificates: 3 }, _suffix: true
|
||||
|
||||
attribute :default_branch_protection_defaults, default: -> { {} }
|
||||
|
||||
|
|
|
|||
|
|
@ -61,8 +61,6 @@ module Namespaces
|
|||
# INPUT: [[4909902], [4909902,51065789], [4909902,51065793], [7135830], [15599674, 1], [15599674, 1, 3], [15599674, 2]]
|
||||
# RESULT: [[4909902], [7135830], [15599674, 1], [15599674, 2]]
|
||||
def shortest_traversal_ids_prefixes
|
||||
raise ArgumentError, 'Feature not supported since the `:use_traversal_ids` is disabled' unless use_traversal_ids?
|
||||
|
||||
prefixes = []
|
||||
|
||||
# The array needs to be sorted (O(nlogn)) to ensure shortest elements are always first
|
||||
|
|
@ -91,8 +89,6 @@ module Namespaces
|
|||
end
|
||||
|
||||
def use_traversal_ids?
|
||||
return false unless Feature.enabled?(:use_traversal_ids)
|
||||
|
||||
traversal_ids.present?
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -12,14 +12,10 @@ module Namespaces
|
|||
# list of namespace IDs, it can be faster to reference the ID in
|
||||
# traversal_ids than the primary key ID column.
|
||||
def as_ids
|
||||
return super unless use_traversal_ids?
|
||||
|
||||
select(Arel.sql('namespaces.traversal_ids[array_length(namespaces.traversal_ids, 1)]').as('id'))
|
||||
end
|
||||
|
||||
def roots
|
||||
return super unless use_traversal_ids?
|
||||
|
||||
root_ids = all.select("#{quoted_table_name}.traversal_ids[1]").distinct
|
||||
unscoped.where(id: root_ids)
|
||||
end
|
||||
|
|
@ -37,20 +33,14 @@ module Namespaces
|
|||
end
|
||||
|
||||
def self_and_descendants(include_self: true)
|
||||
return super unless use_traversal_ids?
|
||||
|
||||
self_and_descendants_with_comparison_operators(include_self: include_self)
|
||||
end
|
||||
|
||||
def self_and_descendant_ids(include_self: true)
|
||||
return super unless use_traversal_ids?
|
||||
|
||||
self_and_descendants(include_self: include_self).as_ids
|
||||
end
|
||||
|
||||
def self_and_hierarchy
|
||||
return super unless use_traversal_ids?
|
||||
|
||||
unscoped.from_union([all.self_and_ancestors, all.self_and_descendants(include_self: false)])
|
||||
end
|
||||
|
||||
|
|
@ -74,10 +64,6 @@ module Namespaces
|
|||
|
||||
private
|
||||
|
||||
def use_traversal_ids?
|
||||
Feature.enabled?(:use_traversal_ids)
|
||||
end
|
||||
|
||||
def self_and_ancestors_from_inner_join(include_self: true, upto: nil, hierarchy_order: nil)
|
||||
base_cte = all.reselect('namespaces.traversal_ids').as_cte(:base_ancestors_cte)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ module Preloaders
|
|||
end
|
||||
|
||||
def execute
|
||||
return unless ::Feature.enabled?(:use_traversal_ids)
|
||||
|
||||
# type == 'Group' condition located on subquery to prevent a filter in the query
|
||||
root_query = Namespace.joins("INNER JOIN (#{join_sql}) as root_query ON root_query.root_id = namespaces.id")
|
||||
.select('namespaces.*, root_query.id as source_id')
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ module Preloaders
|
|||
|
||||
def execute
|
||||
return unless @projects.is_a?(ActiveRecord::Relation)
|
||||
return unless ::Feature.enabled?(:use_traversal_ids)
|
||||
|
||||
root_query = Namespace.joins("INNER JOIN (#{join_sql}) as root_query ON root_query.root_id = namespaces.id")
|
||||
.select('namespaces.*, root_query.id as source_id')
|
||||
|
|
|
|||
|
|
@ -10,27 +10,11 @@ module Preloaders
|
|||
end
|
||||
|
||||
def execute
|
||||
if ::Feature.enabled?(:use_traversal_ids)
|
||||
preload_with_traversal_ids
|
||||
else
|
||||
preload_direct_memberships
|
||||
end
|
||||
preload_with_traversal_ids
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def preload_direct_memberships
|
||||
group_memberships = GroupMember.active_without_invites_and_requests
|
||||
.where(user: @user, source_id: @groups)
|
||||
.group(:source_id)
|
||||
.maximum(:access_level)
|
||||
|
||||
@groups.each do |group|
|
||||
access_level = group_memberships[group.id]
|
||||
group.merge_value_to_request_store(User, @user.id, access_level) if access_level.present?
|
||||
end
|
||||
end
|
||||
|
||||
def preload_with_traversal_ids
|
||||
# Diagrammatic representation of this step:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111157#note_1271550140
|
||||
|
|
|
|||
|
|
@ -2509,14 +2509,6 @@ class User < MainClusterwide::ApplicationRecord
|
|||
def ci_namespace_mirrors_for_group_members(level)
|
||||
search_members = group_members.where('access_level >= ?', level)
|
||||
|
||||
# This reduces searched prefixes to only shortest ones
|
||||
# to avoid querying descendants since they are already covered
|
||||
# by ancestor namespaces. If the FF is not available fallback to
|
||||
# inefficient search: https://gitlab.com/gitlab-org/gitlab/-/issues/336436
|
||||
unless Feature.enabled?(:use_traversal_ids)
|
||||
return Ci::NamespaceMirror.contains_any_of_namespaces(search_members.pluck(:source_id))
|
||||
end
|
||||
|
||||
traversal_ids = Group.joins(:all_group_members)
|
||||
.merge(search_members)
|
||||
.shortest_traversal_ids_prefixes
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
- if group.root?
|
||||
.form-group
|
||||
= f.label _('Enabled Git access protocols'), class: 'label-bold'
|
||||
= f.select :enabled_git_access_protocol, options_for_select(enabled_git_access_protocol_options_for_group, group.enabled_git_access_protocol), {}, class: 'form-control', data: { qa_selector: 'enabled_git_access_protocol_dropdown' }, disabled: !::Gitlab::CurrentSettings.enabled_git_access_protocol.blank?
|
||||
= f.select :enabled_git_access_protocol, options_for_select(enabled_git_access_protocol_options_for_group(group), group.enabled_git_access_protocol), {}, class: 'form-control', data: { qa_selector: 'enabled_git_access_protocol_dropdown' }, disabled: !::Gitlab::CurrentSettings.enabled_git_access_protocol.blank?
|
||||
- if !::Gitlab::CurrentSettings.enabled_git_access_protocol.blank?
|
||||
.form-text.text-muted
|
||||
= _("This setting has been configured at the instance level and cannot be overridden per group")
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: use_traversal_ids
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56296
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321948
|
||||
milestone: '13.11'
|
||||
name: enforce_ssh_certificates
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132653
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/426235
|
||||
milestone: '16.5'
|
||||
type: development
|
||||
group: group::tenant scale
|
||||
default_enabled: true
|
||||
group: group::source code
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
table_name: scan_result_policy_violations
|
||||
classes:
|
||||
- Security::ScanResultPolicyViolation
|
||||
feature_categories:
|
||||
- security_policy_management
|
||||
description: Stores scan result policy violations.
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132254
|
||||
milestone: '16.5'
|
||||
gitlab_schema: gitlab_main
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateScanResultPolicyViolations < Gitlab::Database::Migration[2.1]
|
||||
enable_lock_retries!
|
||||
|
||||
def up
|
||||
create_table :scan_result_policy_violations do |t|
|
||||
t.bigint :scan_result_policy_id,
|
||||
index: false,
|
||||
null: false
|
||||
|
||||
t.bigint :merge_request_id,
|
||||
index: { name: 'index_scan_result_policy_violations_on_merge_request_id' },
|
||||
null: false
|
||||
|
||||
t.bigint :project_id,
|
||||
index: { name: 'index_scan_result_policy_violations_on_project_id' },
|
||||
null: false
|
||||
|
||||
t.timestamps_with_timezone null: false
|
||||
end
|
||||
|
||||
add_index(:scan_result_policy_violations,
|
||||
%i[scan_result_policy_id merge_request_id],
|
||||
unique: true,
|
||||
name: 'index_scan_result_policy_violations_on_policy_and_merge_request')
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :scan_result_policy_violations
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddScanResultPolicyFkToScanResultPolicyViolations < Gitlab::Database::Migration[2.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_foreign_key(
|
||||
:scan_result_policy_violations,
|
||||
:scan_result_policies,
|
||||
column: :scan_result_policy_id,
|
||||
on_delete: :cascade)
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_foreign_key(:scan_result_policy_violations, column: :scan_result_policy_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddMergeRequestFkToScanResultPolicyViolations < Gitlab::Database::Migration[2.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_foreign_key(
|
||||
:scan_result_policy_violations,
|
||||
:merge_requests,
|
||||
column: :merge_request_id,
|
||||
on_delete: :cascade)
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_foreign_key(:scan_result_policy_violations, column: :merge_request_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddProjectFkToScanResultPolicyViolations < Gitlab::Database::Migration[2.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_foreign_key(
|
||||
:scan_result_policy_violations,
|
||||
:projects,
|
||||
column: :project_id,
|
||||
on_delete: :cascade)
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_foreign_key(:scan_result_policy_violations, column: :project_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DeletePagesDomainWithReservedDomains < Gitlab::Database::Migration[2.1]
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
def up
|
||||
execute <<~SQL.squish
|
||||
DELETE FROM "pages_domains"
|
||||
WHERE LOWER("pages_domains"."domain") IN
|
||||
('aol.com', 'gmail.com', 'hotmail.co.uk', 'hotmail.com', 'hotmail.fr', 'icloud.com',
|
||||
'live.com', 'mail.com', 'me.com', 'msn.com', 'outlook.com', 'proton.me', 'protonmail.com',
|
||||
'tutanota.com', 'yahoo.com', 'yandex.com', 'zohomail.com');
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
# This migration can't be rolled back as we are deleting entires
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ChangeWorkspacesForceIncludeAllResourcesDefault < Gitlab::Database::Migration[2.1]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
change_column_default(:workspaces, :force_include_all_resources, from: false, to: true)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
fdc307e3bd5e7762d276219fe877c8b2dd94c90117d914b483c624fc28f4b7dd
|
||||
|
|
@ -0,0 +1 @@
|
|||
5890e80dd082fbef80ec5772597f90486defd9055b9506e588ac5c63f55d69e7
|
||||
|
|
@ -0,0 +1 @@
|
|||
6279203061e730ad1e6b969d55cc7aa78c0cca943beaad66852552f72511aba6
|
||||
|
|
@ -0,0 +1 @@
|
|||
4c391db76b7cf1d380beb4317db727d01372da47e7a97be1bf52f9a791ed0b89
|
||||
|
|
@ -0,0 +1 @@
|
|||
7f51d5f2f6382dc2b48a766e32b5248846a912a47158872c1c26524127b08c61
|
||||
|
|
@ -0,0 +1 @@
|
|||
7d7349723ad38ef6615437d563b01aff39b6eb1c58ec29601e770330d0d5ada6
|
||||
|
|
@ -22754,6 +22754,24 @@ CREATE SEQUENCE scan_result_policies_id_seq
|
|||
|
||||
ALTER SEQUENCE scan_result_policies_id_seq OWNED BY scan_result_policies.id;
|
||||
|
||||
CREATE TABLE scan_result_policy_violations (
|
||||
id bigint NOT NULL,
|
||||
scan_result_policy_id bigint NOT NULL,
|
||||
merge_request_id bigint NOT NULL,
|
||||
project_id bigint NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE scan_result_policy_violations_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE scan_result_policy_violations_id_seq OWNED BY scan_result_policy_violations.id;
|
||||
|
||||
CREATE TABLE schema_migrations (
|
||||
version character varying NOT NULL,
|
||||
finished_at timestamp with time zone DEFAULT now()
|
||||
|
|
@ -25244,7 +25262,7 @@ CREATE TABLE workspaces (
|
|||
personal_access_token_id bigint,
|
||||
config_version integer DEFAULT 1 NOT NULL,
|
||||
force_full_reconciliation boolean DEFAULT false NOT NULL,
|
||||
force_include_all_resources boolean DEFAULT false NOT NULL,
|
||||
force_include_all_resources boolean DEFAULT true NOT NULL,
|
||||
CONSTRAINT check_15543fb0fa CHECK ((char_length(name) <= 64)),
|
||||
CONSTRAINT check_157d5f955c CHECK ((char_length(namespace) <= 64)),
|
||||
CONSTRAINT check_2b401b0034 CHECK ((char_length(deployment_resource_version) <= 64)),
|
||||
|
|
@ -26736,6 +26754,8 @@ ALTER TABLE ONLY sbom_sources ALTER COLUMN id SET DEFAULT nextval('sbom_sources_
|
|||
|
||||
ALTER TABLE ONLY scan_result_policies ALTER COLUMN id SET DEFAULT nextval('scan_result_policies_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY scan_result_policy_violations ALTER COLUMN id SET DEFAULT nextval('scan_result_policy_violations_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY scim_identities ALTER COLUMN id SET DEFAULT nextval('scim_identities_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY scim_oauth_access_tokens ALTER COLUMN id SET DEFAULT nextval('scim_oauth_access_tokens_id_seq'::regclass);
|
||||
|
|
@ -29235,6 +29255,9 @@ ALTER TABLE ONLY sbom_sources
|
|||
ALTER TABLE ONLY scan_result_policies
|
||||
ADD CONSTRAINT scan_result_policies_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY scan_result_policy_violations
|
||||
ADD CONSTRAINT scan_result_policy_violations_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY schema_migrations
|
||||
ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);
|
||||
|
||||
|
|
@ -33989,6 +34012,12 @@ CREATE UNIQUE INDEX index_scan_result_policies_on_position_in_configuration ON s
|
|||
|
||||
CREATE INDEX index_scan_result_policies_on_project_id ON scan_result_policies USING btree (project_id);
|
||||
|
||||
CREATE INDEX index_scan_result_policy_violations_on_merge_request_id ON scan_result_policy_violations USING btree (merge_request_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_scan_result_policy_violations_on_policy_and_merge_request ON scan_result_policy_violations USING btree (scan_result_policy_id, merge_request_id);
|
||||
|
||||
CREATE INDEX index_scan_result_policy_violations_on_project_id ON scan_result_policy_violations USING btree (project_id);
|
||||
|
||||
CREATE INDEX index_scim_identities_on_group_id ON scim_identities USING btree (group_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_scim_identities_on_lower_extern_uid_and_group_id ON scim_identities USING btree (lower((extern_uid)::text), group_id);
|
||||
|
|
@ -36710,6 +36739,9 @@ ALTER TABLE ONLY internal_ids
|
|||
ALTER TABLE ONLY incident_management_timeline_events
|
||||
ADD CONSTRAINT fk_17a5fafbd4 FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY scan_result_policy_violations
|
||||
ADD CONSTRAINT fk_17ce579abf FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY incident_management_timeline_events
|
||||
ADD CONSTRAINT fk_1800597ef9 FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE SET NULL;
|
||||
|
||||
|
|
@ -37091,6 +37123,9 @@ ALTER TABLE ONLY notes
|
|||
ALTER TABLE ONLY oauth_openid_requests
|
||||
ADD CONSTRAINT fk_77114b3b09 FOREIGN KEY (access_grant_id) REFERENCES oauth_access_grants(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY scan_result_policy_violations
|
||||
ADD CONSTRAINT fk_77251168f1 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY agent_user_access_project_authorizations
|
||||
ADD CONSTRAINT fk_78034b05d8 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
@ -37673,6 +37708,9 @@ ALTER TABLE ONLY status_check_responses
|
|||
ALTER TABLE ONLY design_management_designs_versions
|
||||
ADD CONSTRAINT fk_f4d25ba00c FOREIGN KEY (version_id) REFERENCES design_management_versions(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY scan_result_policy_violations
|
||||
ADD CONSTRAINT fk_f53706dbdd FOREIGN KEY (scan_result_policy_id) REFERENCES scan_result_policies(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY analytics_devops_adoption_segments
|
||||
ADD CONSTRAINT fk_f5aa768998 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -1195,6 +1195,8 @@ There are two ways to fix this:
|
|||
|
||||
###### Environment variable overrides
|
||||
|
||||
> Multiple databases support was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/133177) in GitLab 16.5.
|
||||
|
||||
By default, GitLab uses the database configuration stored in a
|
||||
configuration file (`database.yml`). However, you can override the database settings
|
||||
for the backup and restore task by setting environment
|
||||
|
|
@ -1218,6 +1220,15 @@ and port 5432 with the Linux package (Omnibus):
|
|||
sudo GITLAB_BACKUP_PGHOST=192.168.1.10 GITLAB_BACKUP_PGPORT=5432 /opt/gitlab/bin/gitlab-backup create
|
||||
```
|
||||
|
||||
If you run GitLab on [multiple databases](../postgresql/multiple_databases.md), you can override database settings by including
|
||||
the database name in the environment variable. For example if your `main` and `ci` databases are
|
||||
hosted on different database servers, you would append their name after the `GITLAB_BACKUP_` prefix,
|
||||
leaving the `PG*` names as is:
|
||||
|
||||
```shell
|
||||
sudo GITLAB_BACKUP_MAIN_PGHOST=192.168.1.10 GITLAB_BACKUP_CI_PGHOST=192.168.1.12 /opt/gitlab/bin/gitlab-backup create
|
||||
```
|
||||
|
||||
See the [PostgreSQL documentation](https://www.postgresql.org/docs/12/libpq-envars.html)
|
||||
for more details on what these parameters do.
|
||||
|
||||
|
|
|
|||
|
|
@ -7954,6 +7954,30 @@ The edge type for [`Achievement`](#achievement).
|
|||
| <a id="achievementedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="achievementedgenode"></a>`node` | [`Achievement`](#achievement) | The item at the end of the edge. |
|
||||
|
||||
#### `AddOnUserConnection`
|
||||
|
||||
The connection type for [`AddOnUser`](#addonuser).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="addonuserconnectioncount"></a>`count` | [`Int!`](#int) | Total count of collection. |
|
||||
| <a id="addonuserconnectionedges"></a>`edges` | [`[AddOnUserEdge]`](#addonuseredge) | A list of edges. |
|
||||
| <a id="addonuserconnectionnodes"></a>`nodes` | [`[AddOnUser]`](#addonuser) | A list of nodes. |
|
||||
| <a id="addonuserconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
||||
|
||||
#### `AddOnUserEdge`
|
||||
|
||||
The edge type for [`AddOnUser`](#addonuser).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="addonuseredgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="addonuseredgenode"></a>`node` | [`AddOnUser`](#addonuser) | The item at the end of the edge. |
|
||||
|
||||
#### `AgentConfigurationConnection`
|
||||
|
||||
The connection type for [`AgentConfiguration`](#agentconfiguration).
|
||||
|
|
@ -12854,6 +12878,8 @@ A user with add-on data.
|
|||
| <a id="addonuserid"></a>`id` | [`ID!`](#id) | ID of the user. |
|
||||
| <a id="addonuseride"></a>`ide` | [`Ide`](#ide) | IDE settings. |
|
||||
| <a id="addonuserjobtitle"></a>`jobTitle` | [`String`](#string) | Job title of the user. |
|
||||
| <a id="addonuserlastactivityon"></a>`lastActivityOn` | [`Date`](#date) | Date the user last performed any actions. |
|
||||
| <a id="addonuserlastloginat"></a>`lastLoginAt` | [`Time`](#time) | Timestamp of the last sign in. |
|
||||
| <a id="addonuserlinkedin"></a>`linkedin` | [`String`](#string) | LinkedIn profile name of the user. |
|
||||
| <a id="addonuserlocation"></a>`location` | [`String`](#string) | Location of the user. |
|
||||
| <a id="addonusername"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. |
|
||||
|
|
@ -13207,7 +13233,6 @@ Describes an alert from the project's Alert Management.
|
|||
| <a id="alertmanagementalertissueiid"></a>`issueIid` **{warning-solid}** | [`ID`](#id) | **Deprecated** in 13.10. Use issue field. |
|
||||
| <a id="alertmanagementalertmetricsdashboardurl"></a>`metricsDashboardUrl` **{warning-solid}** | [`String`](#string) | **Deprecated** in 16.0. Returns no data. Underlying feature was removed in 16.0. |
|
||||
| <a id="alertmanagementalertmonitoringtool"></a>`monitoringTool` | [`String`](#string) | Monitoring tool the alert came from. |
|
||||
| <a id="alertmanagementalertnotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="alertmanagementalertprometheusalert"></a>`prometheusAlert` | [`PrometheusAlert`](#prometheusalert) | Alert condition for Prometheus. |
|
||||
| <a id="alertmanagementalertrunbook"></a>`runbook` | [`String`](#string) | Runbook for the alert as defined in alert details. |
|
||||
| <a id="alertmanagementalertservice"></a>`service` | [`String`](#string) | Service the alert came from. |
|
||||
|
|
@ -13220,6 +13245,22 @@ Describes an alert from the project's Alert Management.
|
|||
|
||||
#### Fields with arguments
|
||||
|
||||
##### `AlertManagementAlert.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="alertmanagementalertnotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
##### `AlertManagementAlert.todos`
|
||||
|
||||
To-do items of the current user for the alert.
|
||||
|
|
@ -13905,7 +13946,6 @@ Represents an epic on an issue board.
|
|||
| <a id="boardepiciid"></a>`iid` | [`ID!`](#id) | Internal ID of the epic. |
|
||||
| <a id="boardepicissues"></a>`issues` | [`EpicIssueConnection`](#epicissueconnection) | A list of issues associated with the epic. (see [Connections](#connections)) |
|
||||
| <a id="boardepiclabels"></a>`labels` | [`LabelConnection`](#labelconnection) | Labels assigned to the epic. (see [Connections](#connections)) |
|
||||
| <a id="boardepicnotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="boardepicparent"></a>`parent` | [`Epic`](#epic) | Parent epic of the epic. |
|
||||
| <a id="boardepicparticipants"></a>`participants` | [`UserCoreConnection`](#usercoreconnection) | List of participants for the epic. (see [Connections](#connections)) |
|
||||
| <a id="boardepicrelationpath"></a>`relationPath` | [`String`](#string) | URI path of the epic-issue relationship. |
|
||||
|
|
@ -14021,6 +14061,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="boardepiccurrentusertodosstate"></a>`state` | [`TodoStateEnum`](#todostateenum) | State of the to-do items. |
|
||||
|
||||
##### `BoardEpic.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="boardepicnotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
##### `BoardEpic.reference`
|
||||
|
||||
Internal reference of the epic. Returned in shortened format by default.
|
||||
|
|
@ -15904,7 +15960,6 @@ A single design.
|
|||
| <a id="designimage"></a>`image` | [`String!`](#string) | URL of the full-sized image. |
|
||||
| <a id="designimagev432x230"></a>`imageV432x230` | [`String`](#string) | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated. |
|
||||
| <a id="designissue"></a>`issue` | [`Issue!`](#issue) | Issue the design belongs to. |
|
||||
| <a id="designnotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="designnotescount"></a>`notesCount` | [`Int!`](#int) | Total count of user-created notes for this design. |
|
||||
| <a id="designproject"></a>`project` | [`Project!`](#project) | Project the design belongs to. |
|
||||
| <a id="designweburl"></a>`webUrl` | [`String!`](#string) | URL of the design. |
|
||||
|
|
@ -15927,6 +15982,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="designcurrentusertodosstate"></a>`state` | [`TodoStateEnum`](#todostateenum) | State of the to-do items. |
|
||||
|
||||
##### `Design.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="designnotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
##### `Design.versions`
|
||||
|
||||
All versions related to this design ordered newest first.
|
||||
|
|
@ -16494,7 +16565,6 @@ Represents an epic.
|
|||
| <a id="epiciid"></a>`iid` | [`ID!`](#id) | Internal ID of the epic. |
|
||||
| <a id="epicissues"></a>`issues` | [`EpicIssueConnection`](#epicissueconnection) | A list of issues associated with the epic. (see [Connections](#connections)) |
|
||||
| <a id="epiclabels"></a>`labels` | [`LabelConnection`](#labelconnection) | Labels assigned to the epic. (see [Connections](#connections)) |
|
||||
| <a id="epicnotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="epicparent"></a>`parent` | [`Epic`](#epic) | Parent epic of the epic. |
|
||||
| <a id="epicparticipants"></a>`participants` | [`UserCoreConnection`](#usercoreconnection) | List of participants for the epic. (see [Connections](#connections)) |
|
||||
| <a id="epicrelationpath"></a>`relationPath` | [`String`](#string) | URI path of the epic-issue relationship. |
|
||||
|
|
@ -16609,6 +16679,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="epiccurrentusertodosstate"></a>`state` | [`TodoStateEnum`](#todostateenum) | State of the to-do items. |
|
||||
|
||||
##### `Epic.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="epicnotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
##### `Epic.reference`
|
||||
|
||||
Internal reference of the epic. Returned in shortened format by default.
|
||||
|
|
@ -16744,7 +16830,6 @@ Relationship between an epic and an issue.
|
|||
| <a id="epicissuemilestone"></a>`milestone` | [`Milestone`](#milestone) | Milestone of the issue. |
|
||||
| <a id="epicissuemoved"></a>`moved` | [`Boolean`](#boolean) | Indicates if issue got moved from other project. |
|
||||
| <a id="epicissuemovedto"></a>`movedTo` | [`Issue`](#issue) | Updated Issue after it got moved to another project. |
|
||||
| <a id="epicissuenotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="epicissueparticipants"></a>`participants` | [`UserCoreConnection`](#usercoreconnection) | List of participants in the issue. (see [Connections](#connections)) |
|
||||
| <a id="epicissueprojectid"></a>`projectId` | [`Int!`](#int) | ID of the issue project. |
|
||||
| <a id="epicissuerelatedmergerequests"></a>`relatedMergeRequests` | [`MergeRequestConnection`](#mergerequestconnection) | Merge requests related to the issue. This field can only be resolved for one issue in any single request. (see [Connections](#connections)) |
|
||||
|
|
@ -16828,6 +16913,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="epicissueissuableresourcelinksincidentid"></a>`incidentId` | [`IssueID!`](#issueid) | ID of the incident. |
|
||||
|
||||
##### `EpicIssue.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="epicissuenotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
##### `EpicIssue.reference`
|
||||
|
||||
Internal reference of the issue. Returned in shortened format by default.
|
||||
|
|
@ -17551,6 +17652,27 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="groupachievementsids"></a>`ids` | [`[AchievementsAchievementID!]`](#achievementsachievementid) | Filter achievements by IDs. |
|
||||
|
||||
##### `Group.addOnEligibleUsers`
|
||||
|
||||
Users in the namespace hierarchy that add ons are applicable for. This only applies to root namespaces.
|
||||
|
||||
WARNING:
|
||||
**Introduced** in 16.5.
|
||||
This feature is an Experiment. It can be changed or removed at any time.
|
||||
|
||||
Returns [`AddOnUserConnection`](#addonuserconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="groupaddoneligibleusersaddontype"></a>`addOnType` | [`GitlabSubscriptionsAddOnType!`](#gitlabsubscriptionsaddontype) | Type of add on to filter the eligible users by. |
|
||||
| <a id="groupaddoneligibleuserssearch"></a>`search` | [`String`](#string) | Search the user list. |
|
||||
|
||||
##### `Group.addOnPurchase`
|
||||
|
||||
AddOnPurchase associated with the namespace.
|
||||
|
|
@ -19043,7 +19165,6 @@ Describes an issuable resource link for incident issues.
|
|||
| <a id="issuemilestone"></a>`milestone` | [`Milestone`](#milestone) | Milestone of the issue. |
|
||||
| <a id="issuemoved"></a>`moved` | [`Boolean`](#boolean) | Indicates if issue got moved from other project. |
|
||||
| <a id="issuemovedto"></a>`movedTo` | [`Issue`](#issue) | Updated Issue after it got moved to another project. |
|
||||
| <a id="issuenotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="issueparticipants"></a>`participants` | [`UserCoreConnection`](#usercoreconnection) | List of participants in the issue. (see [Connections](#connections)) |
|
||||
| <a id="issueprojectid"></a>`projectId` | [`Int!`](#int) | ID of the issue project. |
|
||||
| <a id="issuerelatedmergerequests"></a>`relatedMergeRequests` | [`MergeRequestConnection`](#mergerequestconnection) | Merge requests related to the issue. This field can only be resolved for one issue in any single request. (see [Connections](#connections)) |
|
||||
|
|
@ -19126,6 +19247,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="issueissuableresourcelinksincidentid"></a>`incidentId` | [`IssueID!`](#issueid) | ID of the incident. |
|
||||
|
||||
##### `Issue.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="issuenotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
##### `Issue.reference`
|
||||
|
||||
Internal reference of the issue. Returned in shortened format by default.
|
||||
|
|
@ -19543,7 +19680,6 @@ Defines which user roles, users, or groups can merge into a protected branch.
|
|||
| <a id="mergerequestmergeablediscussionsstate"></a>`mergeableDiscussionsState` | [`Boolean`](#boolean) | Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged. |
|
||||
| <a id="mergerequestmergedat"></a>`mergedAt` | [`Time`](#time) | Timestamp of when the merge request was merged, null if not merged. |
|
||||
| <a id="mergerequestmilestone"></a>`milestone` | [`Milestone`](#milestone) | Milestone of the merge request. |
|
||||
| <a id="mergerequestnotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="mergerequestparticipants"></a>`participants` | [`MergeRequestParticipantConnection`](#mergerequestparticipantconnection) | Participants in the merge request. This includes the author, assignees, reviewers, and users mentioned in notes. (see [Connections](#connections)) |
|
||||
| <a id="mergerequestpreparedat"></a>`preparedAt` | [`Time`](#time) | Timestamp of when the merge request was prepared. |
|
||||
| <a id="mergerequestproject"></a>`project` | [`Project!`](#project) | Alias for target_project. |
|
||||
|
|
@ -19629,6 +19765,22 @@ Returns [`FindingReportsComparer`](#findingreportscomparer).
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestfindingreportscomparerreporttype"></a>`reportType` | [`ComparableSecurityReportType!`](#comparablesecurityreporttype) | Filter vulnerability findings by report type. |
|
||||
|
||||
##### `MergeRequest.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestnotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
##### `MergeRequest.pipelines`
|
||||
|
||||
Pipelines for the merge request. Note: for performance reasons, no more than the most recent 500 pipelines will be returned.
|
||||
|
|
@ -21026,6 +21178,27 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="namespaceachievementsids"></a>`ids` | [`[AchievementsAchievementID!]`](#achievementsachievementid) | Filter achievements by IDs. |
|
||||
|
||||
##### `Namespace.addOnEligibleUsers`
|
||||
|
||||
Users in the namespace hierarchy that add ons are applicable for. This only applies to root namespaces.
|
||||
|
||||
WARNING:
|
||||
**Introduced** in 16.5.
|
||||
This feature is an Experiment. It can be changed or removed at any time.
|
||||
|
||||
Returns [`AddOnUserConnection`](#addonuserconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="namespaceaddoneligibleusersaddontype"></a>`addOnType` | [`GitlabSubscriptionsAddOnType!`](#gitlabsubscriptionsaddontype) | Type of add on to filter the eligible users by. |
|
||||
| <a id="namespaceaddoneligibleuserssearch"></a>`search` | [`String`](#string) | Search the user list. |
|
||||
|
||||
##### `Namespace.addOnPurchase`
|
||||
|
||||
AddOnPurchase associated with the namespace.
|
||||
|
|
@ -24773,7 +24946,6 @@ Represents a snippet entry.
|
|||
| <a id="snippetfilename"></a>`fileName` | [`String`](#string) | File Name of the snippet. |
|
||||
| <a id="snippethttpurltorepo"></a>`httpUrlToRepo` | [`String`](#string) | HTTP URL to the snippet repository. |
|
||||
| <a id="snippetid"></a>`id` | [`SnippetID!`](#snippetid) | ID of the snippet. |
|
||||
| <a id="snippetnotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="snippetproject"></a>`project` | [`Project`](#project) | Project the snippet is associated with. |
|
||||
| <a id="snippetrawurl"></a>`rawUrl` | [`String!`](#string) | Raw URL of the snippet. |
|
||||
| <a id="snippetsshurltorepo"></a>`sshUrlToRepo` | [`String`](#string) | SSH URL to the snippet repository. |
|
||||
|
|
@ -24801,6 +24973,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="snippetblobspaths"></a>`paths` | [`[String!]`](#string) | Paths of the blobs. |
|
||||
|
||||
##### `Snippet.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="snippetnotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
### `SnippetBlob`
|
||||
|
||||
Represents the snippet blob.
|
||||
|
|
@ -25788,7 +25976,6 @@ Represents a vulnerability.
|
|||
| <a id="vulnerabilitylocation"></a>`location` | [`VulnerabilityLocation`](#vulnerabilitylocation) | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability. |
|
||||
| <a id="vulnerabilitymergerequest"></a>`mergeRequest` | [`MergeRequest`](#mergerequest) | Merge request that fixes the vulnerability. |
|
||||
| <a id="vulnerabilitymessage"></a>`message` **{warning-solid}** | [`String`](#string) | **Deprecated** in 16.1. message field has been removed from security reports schema. |
|
||||
| <a id="vulnerabilitynotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="vulnerabilityprimaryidentifier"></a>`primaryIdentifier` | [`VulnerabilityIdentifier`](#vulnerabilityidentifier) | Primary identifier of the vulnerability. |
|
||||
| <a id="vulnerabilityproject"></a>`project` | [`Project`](#project) | Project on which the vulnerability was found. |
|
||||
| <a id="vulnerabilityreporttype"></a>`reportType` | [`VulnerabilityReportType`](#vulnerabilityreporttype) | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING, API_FUZZING, CLUSTER_IMAGE_SCANNING, GENERIC). `Scan Type` in the UI. |
|
||||
|
|
@ -25827,6 +26014,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="vulnerabilityissuelinkslinktype"></a>`linkType` | [`VulnerabilityIssueLinkType`](#vulnerabilityissuelinktype) | Filter issue links by link type. |
|
||||
|
||||
##### `Vulnerability.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="vulnerabilitynotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
### `VulnerabilityContainerImage`
|
||||
|
||||
Represents a container image reported on the related vulnerability.
|
||||
|
|
@ -27922,6 +28125,14 @@ Geo registry class.
|
|||
| <a id="georegistryclassterraform_state_version_registry"></a>`TERRAFORM_STATE_VERSION_REGISTRY` | Geo::TerraformStateVersionRegistry registry class. |
|
||||
| <a id="georegistryclassupload_registry"></a>`UPLOAD_REGISTRY` | Geo::UploadRegistry registry class. |
|
||||
|
||||
### `GitlabSubscriptionsAddOnType`
|
||||
|
||||
Types of add-ons.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| <a id="gitlabsubscriptionsaddontypecode_suggestions"></a>`CODE_SUGGESTIONS` | Code suggestions seat add-on. |
|
||||
|
||||
### `GitlabSubscriptionsUserRole`
|
||||
|
||||
Role of User.
|
||||
|
|
@ -30600,7 +30811,24 @@ Implementations:
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="noteableinterfacecommenters"></a>`commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="noteableinterfacediscussions"></a>`discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) |
|
||||
| <a id="noteableinterfacenotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
|
||||
|
||||
##### Fields with arguments
|
||||
|
||||
###### `NoteableInterface.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
####### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="noteableinterfacenotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
#### `OrchestrationPolicy`
|
||||
|
||||
|
|
|
|||
|
|
@ -231,9 +231,9 @@ Parameters:
|
|||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `new_issue_url` | string | true | New Issue URL |
|
||||
| `issues_url` | string | true | Issue URL |
|
||||
| `project_url` | string | true | Project URL |
|
||||
| `new_issue_url` | string | true | New issue URL. |
|
||||
| `issues_url` | string | true | Issue URL. |
|
||||
| `project_url` | string | true | Project URL. |
|
||||
|
||||
### Disable Bugzilla
|
||||
|
||||
|
|
@ -371,7 +371,7 @@ Parameters:
|
|||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `confluence_url` | string | true | The URL of the Confluence Cloud Workspace hosted on atlassian.net. |
|
||||
| `confluence_url` | string | true | The URL of the Confluence Workspace hosted on `atlassian.net`. |
|
||||
|
||||
### Disable Confluence Workspace
|
||||
|
||||
|
|
@ -403,9 +403,9 @@ Parameters:
|
|||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `new_issue_url` | string | true | New Issue URL |
|
||||
| `issues_url` | string | true | Issue URL |
|
||||
| `project_url` | string | true | Project URL |
|
||||
| `new_issue_url` | string | true | New issue URL. |
|
||||
| `issues_url` | string | true | Issue URL. |
|
||||
| `project_url` | string | true | Project URL. |
|
||||
|
||||
### Disable a custom issue tracker
|
||||
|
||||
|
|
@ -438,12 +438,12 @@ Parameters:
|
|||
| Parameter | Type | Required | Description |
|
||||
|------------------------|---------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `api_key` | string | true | API key used for authentication with Datadog. |
|
||||
| `api_url` | string | false | (Advanced) The full URL for your Datadog site |
|
||||
| `datadog_env` | string | false | For self-managed deployments, set the env% tag for all the data sent to Datadog. |
|
||||
| `datadog_service` | string | false | Tag all data from this GitLab instance in Datadog. Useful when managing several self-managed deployments |
|
||||
| `datadog_site` | string | false | The Datadog site to send data to. To send data to the EU site, use `datadoghq.eu` |
|
||||
| `datadog_tags` | string | false | Custom tags in Datadog. Specify one tag per line in the format: `key:value\nkey2:value2` ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79665) in GitLab 14.8.) |
|
||||
| `archive_trace_events` | boolean | false | When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346339) in GitLab 15.3) |
|
||||
| `api_url` | string | false | (Advanced) The full URL for your Datadog site. |
|
||||
| `datadog_env` | string | false | For self-managed deployments, set the `env%` tag for all the data sent to Datadog. |
|
||||
| `datadog_service` | string | false | Tag all data from this GitLab instance in Datadog. Can be used when managing several self-managed deployments. |
|
||||
| `datadog_site` | string | false | The Datadog site to send data to. To send data to the EU site, use `datadoghq.eu`. |
|
||||
| `datadog_tags` | string | false | Custom tags in Datadog. Specify one tag per line in the format `key:value\nkey2:value2` ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79665) in GitLab 14.8.). |
|
||||
| `archive_trace_events` | boolean | false | When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346339) in GitLab 15.3). |
|
||||
|
||||
### Disable Datadog
|
||||
|
||||
|
|
@ -480,24 +480,24 @@ Parameters:
|
|||
| `webhook` | string | true | Discord webhook (for example, `https://discord.com/api/webhooks/…`). |
|
||||
| `branches_to_be_notified` | string | false | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. |
|
||||
| `confidential_issues_events` | boolean | false | Enable notifications for confidential issue events. |
|
||||
| `confidential_issue_channel` | string | false | The webhook override to receive confidential issues events notifications. |
|
||||
| `confidential_issue_channel` | string | false | The webhook override to receive notifications for confidential issue events. |
|
||||
| `confidential_note_events` | boolean | false | Enable notifications for confidential note events. |
|
||||
| `confidential_note_channel` | string | false | The webhook override to receive confidential note events notifications. |
|
||||
| `confidential_note_channel` | string | false | The webhook override to receive notifications for confidential note events. |
|
||||
| `issues_events` | boolean | false | Enable notifications for issue events. |
|
||||
| `issue_channel` | string | false | The webhook override to receive issues events notifications. |
|
||||
| `issue_channel` | string | false | The webhook override to receive notifications for issue events. |
|
||||
| `merge_requests_events` | boolean | false | Enable notifications for merge request events. |
|
||||
| `merge_request_channel` | string | false | The webhook override to receive merge request events notifications. |
|
||||
| `merge_request_channel` | string | false | The webhook override to receive notifications for merge request events. |
|
||||
| `note_events` | boolean | false | Enable notifications for note events. |
|
||||
| `note_channel` | string | false | The webhook override to receive note events notifications. |
|
||||
| `note_channel` | string | false | The webhook override to receive notifications for note events. |
|
||||
| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines. |
|
||||
| `pipeline_events` | boolean | false | Enable notifications for pipeline events. |
|
||||
| `pipeline_channel` | string | false | The webhook override to receive pipeline events notifications. |
|
||||
| `pipeline_channel` | string | false | The webhook override to receive notifications for pipeline events. |
|
||||
| `push_events` | boolean | false | Enable notifications for push events. |
|
||||
| `push_channel` | string | false | The webhook override to receive push events notifications. |
|
||||
| `push_channel` | string | false | The webhook override to receive notifications for push events. |
|
||||
| `tag_push_events` | boolean | false | Enable notifications for tag push events. |
|
||||
| `tag_push_channel` | string | false | The webhook override to receive tag push events notifications. |
|
||||
| `tag_push_channel` | string | false | The webhook override to receive notifications for tag push events. |
|
||||
| `wiki_page_events` | boolean | false | Enable notifications for wiki page events. |
|
||||
| `wiki_page_channel` | string | false | The webhook override to receive wiki page events notifications. |
|
||||
| `wiki_page_channel` | string | false | The webhook override to receive notifications for wiki page events. |
|
||||
|
||||
### Disable Discord Notifications
|
||||
|
||||
|
|
@ -637,7 +637,7 @@ Parameters:
|
|||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `external_wiki_url` | string | true | The URL of the external wiki |
|
||||
| `external_wiki_url` | string | true | The URL of the external wiki. |
|
||||
|
||||
### Disable an external wiki
|
||||
|
||||
|
|
@ -707,33 +707,33 @@ Parameters:
|
|||
| `username` | string | false | username. |
|
||||
| `channel` | string | false | Default channel to use if others are not configured. |
|
||||
| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines. |
|
||||
| `notify_only_default_branch` | boolean | false | DEPRECATED: This parameter has been replaced with `branches_to_be_notified`. |
|
||||
| `notify_only_default_branch` | boolean | false | **Deprecated:** This parameter has been replaced with `branches_to_be_notified`. |
|
||||
| `branches_to_be_notified` | string | false | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. |
|
||||
| `alert_channel` | string | false | The name of the channel to receive alert events notifications. |
|
||||
| `alert_channel` | string | false | The name of the channel to receive notifications for alert events. |
|
||||
| `alert_events` | boolean | false | Enable notifications for alert events. |
|
||||
| `commit_events` | boolean | false | Enable notifications for commit events. |
|
||||
| `confidential_issue_channel` | string | false | The name of the channel to receive confidential issues events notifications. |
|
||||
| `confidential_issue_channel` | string | false | The name of the channel to receive notifications for confidential issue events. |
|
||||
| `confidential_issues_events` | boolean | false | Enable notifications for confidential issue events. |
|
||||
| `confidential_note_channel` | string | false | The name of the channel to receive confidential note events notifications. |
|
||||
| `confidential_note_channel` | string | false | The name of the channel to receive notifications for confidential note events. |
|
||||
| `confidential_note_events` | boolean | false | Enable notifications for confidential note events. |
|
||||
| `deployment_channel` | string | false | The name of the channel to receive deployment events notifications. |
|
||||
| `deployment_channel` | string | false | The name of the channel to receive notifications for deployment events. |
|
||||
| `deployment_events` | boolean | false | Enable notifications for deployment events. |
|
||||
| `incident_channel` | string | false | The name of the channel to receive incidents events notifications. |
|
||||
| `incident_channel` | string | false | The name of the channel to receive notifications for incident events. |
|
||||
| `incidents_events` | boolean | false | Enable notifications for incident events. |
|
||||
| `issue_channel` | string | false | The name of the channel to receive issues events notifications. |
|
||||
| `issue_channel` | string | false | The name of the channel to receive notifications for issue events. |
|
||||
| `issues_events` | boolean | false | Enable notifications for issue events. |
|
||||
| `job_events` | boolean | false | Enable notifications for job events. |
|
||||
| `merge_request_channel` | string | false | The name of the channel to receive merge request events notifications. |
|
||||
| `merge_request_channel` | string | false | The name of the channel to receive notifications for merge request events. |
|
||||
| `merge_requests_events` | boolean | false | Enable notifications for merge request events. |
|
||||
| `note_channel` | string | false | The name of the channel to receive note events notifications. |
|
||||
| `note_channel` | string | false | The name of the channel to receive notifications for note events. |
|
||||
| `note_events` | boolean | false | Enable notifications for note events. |
|
||||
| `pipeline_channel` | string | false | The name of the channel to receive pipeline events notifications. |
|
||||
| `pipeline_channel` | string | false | The name of the channel to receive notifications for pipeline events. |
|
||||
| `pipeline_events` | boolean | false | Enable notifications for pipeline events. |
|
||||
| `push_channel` | string | false | The name of the channel to receive push events notifications. |
|
||||
| `push_channel` | string | false | The name of the channel to receive notifications for push events. |
|
||||
| `push_events` | boolean | false | Enable notifications for push events. |
|
||||
| `tag_push_channel` | string | false | The name of the channel to receive tag push events notifications. |
|
||||
| `tag_push_channel` | string | false | The name of the channel to receive notifications for tag push events. |
|
||||
| `tag_push_events` | boolean | false | Enable notifications for tag push events. |
|
||||
| `wiki_page_channel` | string | false | The name of the channel to receive wiki page events notifications. |
|
||||
| `wiki_page_channel` | string | false | The name of the channel to receive notifications for wiki page events. |
|
||||
| `wiki_page_events` | boolean | false | Enable notifications for wiki page events. |
|
||||
|
||||
### Disable the GitLab for Slack app
|
||||
|
|
@ -768,7 +768,7 @@ Parameters:
|
|||
| --------- | ---- | -------- | ----------- |
|
||||
| `webhook` | string | true | The Hangouts Chat webhook (for example, `https://chat.googleapis.com/v1/spaces...`). |
|
||||
| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines. |
|
||||
| `notify_only_default_branch` | boolean | false | DEPRECATED: This parameter has been replaced with `branches_to_be_notified`. |
|
||||
| `notify_only_default_branch` | boolean | false | **Deprecated:** This parameter has been replaced with `branches_to_be_notified`. |
|
||||
| `branches_to_be_notified` | string | false | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. |
|
||||
| `push_events` | boolean | false | Enable notifications for push events. |
|
||||
| `issues_events` | boolean | false | Enable notifications for issue events. |
|
||||
|
|
@ -810,11 +810,11 @@ Parameters:
|
|||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `recipients` | string | true | Recipients/channels separated by whitespaces |
|
||||
| `default_irc_uri` | string | false | `irc://irc.network.net:6697/` |
|
||||
| `server_host` | string | false | localhost |
|
||||
| `server_port` | integer | false | 6659 |
|
||||
| `colorize_messages` | boolean | false | Colorize messages |
|
||||
| `recipients` | string | true | Recipients or channels separated by whitespaces. |
|
||||
| `default_irc_uri` | string | false | `irc://irc.network.net:6697/`. |
|
||||
| `server_host` | string | false | localhost. |
|
||||
| `server_port` | integer | false | 6659. |
|
||||
| `colorize_messages` | boolean | false | Colorize messages. |
|
||||
|
||||
### Disable irker
|
||||
|
||||
|
|
@ -938,7 +938,7 @@ Parameters:
|
|||
| `jira_issue_transition_id` | string | no | The ID of one or more transitions for [custom issue transitions](../integration/jira/issues.md#custom-issue-transitions). Ignored if `jira_issue_transition_automatic` is enabled. Defaults to a blank string, which disables custom transitions. |
|
||||
| `commit_events` | boolean | false | Enable notifications for commit events. |
|
||||
| `merge_requests_events` | boolean | false | Enable notifications for merge request events. |
|
||||
| `comment_on_event_enabled` | boolean | false | Enable comments inside Jira issues on each GitLab event (commit / merge request). |
|
||||
| `comment_on_event_enabled` | boolean | false | Enable comments in Jira issues on each GitLab event (commit or merge request). |
|
||||
|
||||
### Disable Jira
|
||||
|
||||
|
|
@ -974,7 +974,7 @@ Parameters:
|
|||
| `username` | string | false | username. |
|
||||
| `channel` | string | false | Default channel to use if others are not configured. |
|
||||
| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines. |
|
||||
| `notify_only_default_branch` | boolean | false | DEPRECATED: This parameter has been replaced with `branches_to_be_notified`. |
|
||||
| `notify_only_default_branch` | boolean | false | **Deprecated:** This parameter has been replaced with `branches_to_be_notified`. |
|
||||
| `branches_to_be_notified` | string | false | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. |
|
||||
| `push_events` | boolean | false | Enable notifications for push events. |
|
||||
| `issues_events` | boolean | false | Enable notifications for issue events. |
|
||||
|
|
@ -985,15 +985,15 @@ Parameters:
|
|||
| `confidential_note_events` | boolean | false | Enable notifications for confidential note events. |
|
||||
| `pipeline_events` | boolean | false | Enable notifications for pipeline events. |
|
||||
| `wiki_page_events` | boolean | false | Enable notifications for wiki page events. |
|
||||
| `push_channel` | string | false | The name of the channel to receive push events notifications. |
|
||||
| `issue_channel` | string | false | The name of the channel to receive issues events notifications. |
|
||||
| `confidential_issue_channel` | string | false | The name of the channel to receive confidential issues events notifications. |
|
||||
| `merge_request_channel` | string | false | The name of the channel to receive merge request events notifications. |
|
||||
| `note_channel` | string | false | The name of the channel to receive note events notifications. |
|
||||
| `confidential_note_channel` | string | false | The name of the channel to receive confidential note events notifications. |
|
||||
| `tag_push_channel` | string | false | The name of the channel to receive tag push events notifications. |
|
||||
| `pipeline_channel` | string | false | The name of the channel to receive pipeline events notifications. |
|
||||
| `wiki_page_channel` | string | false | The name of the channel to receive wiki page events notifications. |
|
||||
| `push_channel` | string | false | The name of the channel to receive notifications for push events. |
|
||||
| `issue_channel` | string | false | The name of the channel to receive notifications for issue events. |
|
||||
| `confidential_issue_channel` | string | false | The name of the channel to receive notifications for confidential issue events. |
|
||||
| `merge_request_channel` | string | false | The name of the channel to receive notifications for merge request events. |
|
||||
| `note_channel` | string | false | The name of the channel to receive notifications for note events. |
|
||||
| `confidential_note_channel` | string | false | The name of the channel to receive notifications for confidential note events. |
|
||||
| `tag_push_channel` | string | false | The name of the channel to receive notifications for tag push events. |
|
||||
| `pipeline_channel` | string | false | The name of the channel to receive notifications for pipeline events. |
|
||||
| `wiki_page_channel` | string | false | The name of the channel to receive notifications for wiki page events. |
|
||||
|
||||
### Disable Mattermost notifications
|
||||
|
||||
|
|
@ -1059,7 +1059,7 @@ Parameters:
|
|||
| --------- | ---- | -------- | ----------- |
|
||||
| `webhook` | string | true | The Microsoft Teams webhook (for example, `https://outlook.office.com/webhook/...`). |
|
||||
| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines. |
|
||||
| `notify_only_default_branch` | boolean | false | DEPRECATED: This parameter has been replaced with `branches_to_be_notified`. |
|
||||
| `notify_only_default_branch` | boolean | false | **Deprecated:** This parameter has been replaced with `branches_to_be_notified`. |
|
||||
| `branches_to_be_notified` | string | false | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. |
|
||||
| `push_events` | boolean | false | Enable notifications for push events. |
|
||||
| `issues_events` | boolean | false | Enable notifications for issue events. |
|
||||
|
|
@ -1175,9 +1175,9 @@ Parameters:
|
|||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `recipients` | string | yes | Comma-separated list of recipient email addresses. |
|
||||
| `notify_only_broken_pipelines` | boolean | no | Notify only broken pipelines. |
|
||||
| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. |
|
||||
| `branches_to_be_notified` | string | false | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. |
|
||||
| `notify_only_default_branch` | boolean | no | Send notifications only for the default branch. |
|
||||
| `notify_only_default_branch` | boolean | no | Send notifications for the default branch. |
|
||||
| `pipeline_events` | boolean | false | Enable notifications for pipeline events. |
|
||||
|
||||
### Disable pipeline status emails
|
||||
|
|
@ -1322,7 +1322,7 @@ Parameters:
|
|||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `new_issue_url` | string | true | New Issue URL. |
|
||||
| `new_issue_url` | string | true | New issue URL. |
|
||||
| `project_url` | string | true | Project URL. |
|
||||
| `issues_url` | string | true | Issue URL. |
|
||||
|
||||
|
|
@ -1416,7 +1416,7 @@ Parameters:
|
|||
| Parameter | Type | Required | Description |
|
||||
|-------------------------|--------|----------|-------------------------------|
|
||||
| `url` | string | yes | URL of the Squash TM webhook. |
|
||||
| `token` | string | no | Optional token |
|
||||
| `token` | string | no | Optional token. |
|
||||
|
||||
### Disable Squash TM
|
||||
|
||||
|
|
@ -1449,17 +1449,17 @@ Parameters:
|
|||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `token` | string | true | The Telegram bot token (for example, `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`). |
|
||||
| `room` | string | true | Unique identifier for the target chat or the username of the target channel (in the format `@channelusername`) |
|
||||
| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines |
|
||||
| `push_events` | boolean | true | Enable notifications for push events |
|
||||
| `issues_events` | boolean | true | Enable notifications for issue events |
|
||||
| `confidential_issues_events` | boolean | true | Enable notifications for confidential issue events |
|
||||
| `merge_requests_events` | boolean | true | Enable notifications for merge request events |
|
||||
| `tag_push_events` | boolean | true | Enable notifications for tag push events |
|
||||
| `note_events` | boolean | true | Enable notifications for note events |
|
||||
| `confidential_note_events` | boolean | true | Enable notifications for confidential note events |
|
||||
| `pipeline_events` | boolean | true | Enable notifications for pipeline events |
|
||||
| `wiki_page_events` | boolean | true | Enable notifications for wiki page events |
|
||||
| `room` | string | true | Unique identifier for the target chat or the username of the target channel (in the format `@channelusername`). |
|
||||
| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines. |
|
||||
| `push_events` | boolean | true | Enable notifications for push events. |
|
||||
| `issues_events` | boolean | true | Enable notifications for issue events. |
|
||||
| `confidential_issues_events` | boolean | true | Enable notifications for confidential issue events. |
|
||||
| `merge_requests_events` | boolean | true | Enable notifications for merge request events. |
|
||||
| `tag_push_events` | boolean | true | Enable notifications for tag push events. |
|
||||
| `note_events` | boolean | true | Enable notifications for note events. |
|
||||
| `confidential_note_events` | boolean | true | Enable notifications for confidential note events. |
|
||||
| `pipeline_events` | boolean | true | Enable notifications for pipeline events. |
|
||||
| `wiki_page_events` | boolean | true | Enable notifications for wiki page events. |
|
||||
|
||||
### Disable Telegram
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
Notes are comments on:
|
||||
|
||||
- Snippets
|
||||
- Issues
|
||||
- Merge requests
|
||||
- [Commits](../user/project/repository/index.md#commit-changes-to-a-repository)
|
||||
- [Epics](../user/group/epics/index.md)
|
||||
- [Issues](../user/project/issues/index.md)
|
||||
- [Merge requests](../user/project/merge_requests/index.md)
|
||||
- [Snippets](../user/snippets.md)
|
||||
|
||||
This includes system notes, which are notes about changes to the object (for example, when an
|
||||
assignee changes, GitLab posts a system note).
|
||||
|
|
|
|||
|
|
@ -7,81 +7,469 @@ type: index, howto
|
|||
|
||||
# Migrating from Jenkins **(FREE ALL)**
|
||||
|
||||
If you're migrating from Jenkins to GitLab CI/CD, you should be able
|
||||
to create CI/CD pipelines that do everything you need.
|
||||
If you're migrating from Jenkins to GitLab CI/CD, you are able to create CI/CD
|
||||
pipelines that replicate and enhance your Jenkins workflows.
|
||||
|
||||
You can start by watching the [Migrating from Jenkins to GitLab](https://www.youtube.com/watch?v=RlEVGOpYF5Y)
|
||||
video for examples of:
|
||||
## Key similarities and differences
|
||||
|
||||
- Converting a Jenkins pipeline into a GitLab CI/CD pipeline.
|
||||
- Using Auto DevOps to test your code automatically.
|
||||
GitLab CI/CD and Jenkins are CI/CD tools with some similarities. Both GitLab
|
||||
and Jenkins:
|
||||
|
||||
## Get started
|
||||
- Use stages for collections of jobs.
|
||||
- Support container-based builds.
|
||||
|
||||
The following list of recommended steps was created after observing organizations
|
||||
that were able to quickly complete this migration.
|
||||
Additionally, there are some important differences between the two:
|
||||
|
||||
Before doing any migration work, you should [start with a migration plan](plan_a_migration.md).
|
||||
- GitLab CI/CD pipelines are all configured in a YAML format configuration file.
|
||||
Jenkins uses either a Groovy format configuration file (declarative pipelines)
|
||||
or Jenkins DSL (scripted pipelines).
|
||||
- GitLab can run either on SaaS (cloud) or self-managed deployments. Jenkins deployments must be self-managed.
|
||||
- GitLab provides source code management (SCM) out of the box. Jenkins requires a separate
|
||||
SCM solution to store code.
|
||||
- GitLab provides a built-in container registry. Jenkins requires a separate solution
|
||||
for storing container images.
|
||||
- GitLab provides built-in templates for scanning code. Jenkins requires 3rd party plugins
|
||||
for scanning code.
|
||||
|
||||
Engineers that need to migrate projects to GitLab CI/CD should first review general
|
||||
information about GitLab CI/CD:
|
||||
## Comparison of features and concepts
|
||||
|
||||
- Read about some [key GitLab CI/CD features](#key-gitlab-cicd-features).
|
||||
- Follow tutorials to create:
|
||||
- [Your first GitLab pipeline](../quick_start/index.md).
|
||||
- [A more complex pipeline](../quick_start/tutorial.md) that builds, tests,
|
||||
and deploys a static site.
|
||||
- Review the [`.gitlab-ci.yml` keyword reference](../yaml/index.md).
|
||||
Many Jenkins features and concepts have equivalents in GitLab that offer the same
|
||||
functionality.
|
||||
|
||||
Then you can begin the process of migrating to GitLab CI/CD:
|
||||
### Configuration file
|
||||
|
||||
- Ensure [runners](../runners/index.md) are available, either by using shared GitLab.com runners
|
||||
or installing new runners.
|
||||
- Migrate build and CI jobs and configure them to show results directly in merge requests.
|
||||
You can use [Auto DevOps](../../topics/autodevops/index.md) as a starting point,
|
||||
and [customize](../../topics/autodevops/customize.md) or [decompose](../../topics/autodevops/customize.md#use-individual-components-of-auto-devops)
|
||||
the configuration as needed.
|
||||
- Migrate deployment jobs by using [cloud deployment templates](../cloud_deployment/index.md),
|
||||
[environments](../environments/index.md), and the [GitLab agent for Kubernetes](../../user/clusters/agent/index.md).
|
||||
- Check if any CI/CD configuration can be reused across different projects, then create
|
||||
and share [templates](#templates).
|
||||
- Check the [pipeline efficiency documentation](../pipelines/pipeline_efficiency.md)
|
||||
to learn how to make your GitLab CI/CD pipelines faster and more efficient.
|
||||
Jenkins can be configured with a [`Jenkinsfile` in the Groovy format](https://www.jenkins.io/doc/book/pipeline/jenkinsfile/). GitLab CI/CD uses a [`.gitlab-ci.yml` YAML file](../../ci/yaml/gitlab_ci_yaml.md) by default.
|
||||
|
||||
If you have questions that are not answered here, the [GitLab community forum](https://forum.gitlab.com/)
|
||||
can be a great resource.
|
||||
Example of a `Jenkinsfile`:
|
||||
|
||||
### Key GitLab CI/CD features
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
GitLab CI/CD key features might be different or not exist in Jenkins. For example,
|
||||
in GitLab:
|
||||
stages {
|
||||
stage('hello') {
|
||||
steps {
|
||||
echo "Hello World"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Pipelines can be triggered with:
|
||||
- A Git push
|
||||
- A [Schedule](../pipelines/schedules.md)
|
||||
- The [GitLab UI](../pipelines/index.md#run-a-pipeline-manually)
|
||||
- An [API call](../triggers/index.md)
|
||||
- A [webhook](../triggers/index.md#use-a-webhook)
|
||||
- You can control which jobs run in which cases with the [`rules` syntax](../yaml/index.md#rules).
|
||||
- You can reuse pipeline configurations:
|
||||
- Use the [`extends` keyword](../yaml/index.md#extends) to reuse configuration
|
||||
in a single pipeline configuration.
|
||||
- Use the [`include` keyword](../yaml/index.md#include) to reuse configuration across
|
||||
multiple pipelines and projects.
|
||||
- Jobs are grouped into stages, and jobs in the same stage can run at the same time.
|
||||
Stages run in sequence. Jobs can be configured to run outside of the stage ordering with the
|
||||
[`needs` keyword](../yaml/index.md#needs).
|
||||
- The [`parallel`](../yaml/index.md#parallel) keyword can automatically parallelize tasks,
|
||||
especially tests that support parallelization.
|
||||
- Jobs run independently of each other and have a fresh environment for each job.
|
||||
Passing artifacts between jobs is controlled using the [`artifacts`](../yaml/index.md#artifacts)
|
||||
and [`dependencies`](../yaml/index.md#dependencies) keywords.
|
||||
- The `.gitlab-ci.yml` configuration file exists in your Git repository, like a `Jenkinsfile`,
|
||||
but is [a YAML file](#yaml-configuration-file), not Groovy.
|
||||
- GitLab comes with a [container registry](../../user/packages/container_registry/index.md).
|
||||
You can build and store custom container images to run your jobs in.
|
||||
The equivalent GitLab CI/CD `.gitlab-ci.yml` file would be:
|
||||
|
||||
## Runners
|
||||
```yaml
|
||||
stages:
|
||||
- hello
|
||||
|
||||
hello-job:
|
||||
stage: hello
|
||||
script:
|
||||
- echo "Hello World"
|
||||
```
|
||||
|
||||
### Jenkins pipeline syntax
|
||||
|
||||
A Jenkins configuration is composed of a `pipeline` block with "sections" and "directives".
|
||||
GitLab CI/CD has similar functionality, configured with YAML keywords.
|
||||
|
||||
#### Sections
|
||||
|
||||
| Jenkins | GitLab | Explanation |
|
||||
|----------|----------------|-------------|
|
||||
| `agent` | `image` | Jenkins pipelines execute on agents, and the `agent` section defines how the pipeline executes, and the Docker container to use. GitLab jobs execute on _runners_, and the `image` keyword defines the container to use. You can configure your own runners in Kubernetes or on any host. |
|
||||
| `post` | `after_script` or `stage` | The Jenkins `post` section defines actions that should be performed at the end of a stage or pipeline. In GitLab, use `after_script` for commands to run at the end of a job, and `before_script` for actions to run before the other commands in a job. Use `stage` to select the exact stage a job should run in. GitLab supports both `.pre` and `.post` stages that always run before or after all other defined stages. |
|
||||
| `stages` | `stages` | Jenkins stages are groups of jobs. GitLab CI/CD also uses stages, but it is more flexible. You can have multiple stages each with multiple independent jobs. Use `stages` at the top level to the stages and their execution order, and use `stage` at the job level to define the stage for that job. |
|
||||
| `steps` | `script` | Jenkins `steps` define what to execute. GitLab CI/CD uses a `script` section which is similar. The `script` section is a YAML array with separate entries for each command to run in sequence. |
|
||||
|
||||
#### Directives
|
||||
|
||||
| Jenkins | GitLab | Explanation |
|
||||
|---------------|----------------|-------------|
|
||||
| `environment` | `variables` | Jenkins uses `environment` for environment variables. GitLab CI/CD uses the `variables` keyword to define CI/CD variables that can be used during job execution, but also for more dynamic pipeline configuration. These can also be set in the GitLab UI, under CI/CD settings. |
|
||||
| `options` | Not applicable | Jenkins uses `options` for additional configuration, including timeouts and retry values. GitLab does not need a separate section for options, all configuration is added as CI/CD keywords at the job or pipeline level, for example `timeout` or `retry`. |
|
||||
| `parameters` | Not applicable | In Jenkins, parameters can be required when triggering a pipeline. Parameters are handled in GitLab with CI/CD variables, which can be defined in many places, including the pipeline configuration, project settings, at runtime manually through the UI, or API. |
|
||||
| `triggers` | `rules` | In Jenkins, `triggers` defines when a pipeline should run again, for example through cron notation. GitLab CI/CD can run pipelines automatically for many reasons, including Git changes and merge request updates. Use the `rules` keyword to control which events to run jobs for. Scheduled pipelines are defined in the project settings. |
|
||||
| `tools` | Not applicable | In Jenkins, `tools` defines additional tools to install in the environment. GitLab does not have a similar keyword, as the recommendation is to use container images prebuilt with the exact tools required for your jobs. These images can be cached and can be built to already contain the tools you need for your pipelines. If a job needs additional tools, they can be installed as part of a `before_script` section. |
|
||||
| `input` | Not applicable | In Jenkins, `input` adds a prompt for user input. Similar to `parameters`, inputs are handled in GitLab through CI/CD variables. |
|
||||
| `when` | `rules` | In Jenkins, `when` defines when a stage should be executed. GitLab also has a `when` keyword, which defines whether a job should start running based on the status of earlier jobs, for example if jobs passed or failed. To control when to add jobs to specific pipelines, use `rules`. |
|
||||
|
||||
### Common configurations
|
||||
|
||||
This section goes over commonly used CI/CD configurations, showing how they can be converted
|
||||
from Jenkins to GitLab CI/CD.
|
||||
|
||||
[Jenkins pipelines](https://www.jenkins.io/doc/book/pipeline/) generate automated CI/CD jobs
|
||||
that are triggered when certain event take place, such as a new commit being pushed.
|
||||
A Jenkins pipeline is defined in a `Jenkinsfile`. The GitLab equivalent is the [`.gitlab-ci.yml` configuration file](../../ci/yaml/gitlab_ci_yaml.md).
|
||||
|
||||
Jenkins does not provide a place to store source code, so the `Jenkinsfile` must be stored
|
||||
in a separate source control repository.
|
||||
|
||||
#### Jobs
|
||||
|
||||
Jobs are a set of commands that run in a set sequence to achieve a particular result.
|
||||
|
||||
For example, build a container then deploy it to production, in a `Jenkinsfile`:
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('build') {
|
||||
agent { docker 'golang:alpine' }
|
||||
steps {
|
||||
apk update
|
||||
go build -o bin/hello
|
||||
}
|
||||
post {
|
||||
always {
|
||||
archiveArtifacts artifacts: 'bin/hello'
|
||||
onlyIfSuccessful: true
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('deploy') {
|
||||
agent { docker 'golang:alpine' }
|
||||
when {
|
||||
branch 'staging'
|
||||
}
|
||||
steps {
|
||||
echo "Deploying to staging"
|
||||
scp bin/hello remoteuser@remotehost:/remote/directory
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This example:
|
||||
|
||||
- Uses the `golang:alpine` container image.
|
||||
- Runs a job for building code.
|
||||
- Stores the built executable as an artifact.
|
||||
- Adds a second job to deploy to `staging`, which:
|
||||
- Only exists if the commit targets the `staging` branch.
|
||||
- Starts after the build stage succeeds.
|
||||
- Uses the built executable artifact from the earlier job.
|
||||
|
||||
The equivalent GitLab CI/CD `.gitlab-ci.yml` file would be:
|
||||
|
||||
```yaml
|
||||
default:
|
||||
image: golang:alpine
|
||||
|
||||
stages:
|
||||
- build
|
||||
- deploy
|
||||
|
||||
build-job:
|
||||
stage: build
|
||||
script:
|
||||
- apk update
|
||||
- go build -o bin/hello
|
||||
artifacts:
|
||||
paths:
|
||||
- bin/hello
|
||||
expire_in: 1 week
|
||||
|
||||
deploy-job:
|
||||
stage: deploy
|
||||
script:
|
||||
- echo "Deploying to Staging"
|
||||
- scp bin/hello remoteuser@remotehost:/remote/directory
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == 'staging'
|
||||
artifacts:
|
||||
paths:
|
||||
- bin/hello
|
||||
```
|
||||
|
||||
##### Parallel
|
||||
|
||||
In Jenkins, jobs that are not dependent on previous jobs can run in parallel when
|
||||
added to a `parallel` section.
|
||||
|
||||
For example, in a `Jenkinsfile`:
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Parallel') {
|
||||
parallel {
|
||||
stage('Python') {
|
||||
agent { docker 'python:latest' }
|
||||
steps {
|
||||
sh "python --version"
|
||||
}
|
||||
}
|
||||
stage('Java') {
|
||||
agent { docker 'openjdk:latest' }
|
||||
when {
|
||||
branch 'staging'
|
||||
}
|
||||
steps {
|
||||
sh "java -version"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This example runs a Python and a Java job in parallel, using different container images.
|
||||
The Java job only runs when the `staging` branch is changed.
|
||||
|
||||
The equivalent GitLab CI/CD `.gitlab-ci.yml` file would be:
|
||||
|
||||
```yaml
|
||||
python-version:
|
||||
image: python:latest
|
||||
script:
|
||||
- python --version
|
||||
|
||||
java-version:
|
||||
image: openjdk:latest
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == 'staging'
|
||||
script:
|
||||
- java -version
|
||||
```
|
||||
|
||||
In this case, no extra configuration is needed to make the jobs run in parallel.
|
||||
Jobs run in parallel by default, each on a different runner assuming there are enough runners
|
||||
for all the jobs. The Java job is set to only run when the `staging` branch is changed.
|
||||
|
||||
##### Matrix
|
||||
|
||||
In GitLab you can use a matrix to run a job multiple times in parallel in a single pipeline,
|
||||
but with different variable values for each instance of the job. Jenkins runs the matrix sequentially.
|
||||
|
||||
For example, in a `Jenkinsfile`:
|
||||
|
||||
```groovy
|
||||
matrix {
|
||||
axes {
|
||||
axis {
|
||||
name 'PLATFORM'
|
||||
values 'linux', 'mac', 'windows'
|
||||
}
|
||||
axis {
|
||||
name 'ARCH'
|
||||
values 'x64', 'x86'
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage('build') {
|
||||
echo "Building $PLATFORM for $ARCH"
|
||||
}
|
||||
stage('test') {
|
||||
echo "Building $PLATFORM for $ARCH"
|
||||
}
|
||||
stage('deploy') {
|
||||
echo "Building $PLATFORM for $ARCH"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The equivalent GitLab CI/CD `.gitlab-ci.yml` file would be:
|
||||
|
||||
```yaml
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- deploy
|
||||
|
||||
.parallel-hidden-job:
|
||||
parallel:
|
||||
matrix:
|
||||
- PLATFORM: [linux, mac, windows]
|
||||
ARCH: [x64, x86]
|
||||
|
||||
build-job:
|
||||
extends: .parallel-hidden-job
|
||||
stage: build
|
||||
script:
|
||||
- echo "Building $PLATFORM for $ARCH"
|
||||
|
||||
test-job:
|
||||
extends: .parallel-hidden-job
|
||||
stage: test
|
||||
script:
|
||||
- echo "Testing $PLATFORM for $ARCH"
|
||||
|
||||
deploy-job:
|
||||
extends: .parallel-hidden-job
|
||||
stage: deploy
|
||||
script:
|
||||
- echo "Testing $PLATFORM for $ARCH"
|
||||
```
|
||||
|
||||
#### Container Images
|
||||
|
||||
In GitLab you can [run your CI/CD jobs in separate, isolated Docker containers](../../ci/docker/using_docker_images.md)
|
||||
using the [image](../../ci/yaml/index.md#image) keyword.
|
||||
|
||||
For example, in a `Jenkinsfile`:
|
||||
|
||||
```groovy
|
||||
stage('Version') {
|
||||
agent { docker 'python:latest' }
|
||||
steps {
|
||||
echo 'Hello Python'
|
||||
sh 'python --version'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This example shows commands running in a `python:latest` container.
|
||||
|
||||
The equivalent GitLab CI/CD `.gitlab-ci.yml` file would be:
|
||||
|
||||
```yaml
|
||||
version-job:
|
||||
image: python:latest
|
||||
script:
|
||||
- echo "Hello Python"
|
||||
- python --version
|
||||
```
|
||||
|
||||
#### Variables
|
||||
|
||||
In GitLab, use the `variables` keyword to define [CI/CD variables](../variables/index.md).
|
||||
Use variables to reuse configuration data, have more dynamic configuration, or store important values.
|
||||
Variables can be defined either globally or per job.
|
||||
|
||||
For example, in a `Jenkinsfile`:
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
environment {
|
||||
NAME = 'Fern'
|
||||
}
|
||||
stages {
|
||||
stage('English') {
|
||||
environment {
|
||||
GREETING = 'Hello'
|
||||
}
|
||||
steps {
|
||||
sh 'echo "$GREETING $NAME"'
|
||||
}
|
||||
}
|
||||
stage('Spanish') {
|
||||
environment {
|
||||
GREETING = 'Hola'
|
||||
}
|
||||
steps {
|
||||
sh 'echo "$GREETING $NAME"'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This example shows how variables can be used to pass values to commands in jobs.
|
||||
|
||||
The equivalent GitLab CI/CD `.gitlab-ci.yml` file would be:
|
||||
|
||||
```yaml
|
||||
default:
|
||||
image: alpine:latest
|
||||
|
||||
stages:
|
||||
- greet
|
||||
|
||||
variables:
|
||||
NAME: "Fern"
|
||||
|
||||
english:
|
||||
stage: greet
|
||||
variables:
|
||||
GREETING: "Hello"
|
||||
script:
|
||||
- echo "$GREETING $NAME"
|
||||
|
||||
spanish:
|
||||
stage: greet
|
||||
variables:
|
||||
GREETING: "Hola"
|
||||
script:
|
||||
- echo "$GREETING $NAME"
|
||||
```
|
||||
|
||||
Variables can also be [set in the GitLab UI, in the CI/CD settings](../variables/index.md#define-a-cicd-variable-in-the-ui).
|
||||
In some cases, you can use [protected](../variables/index.md#protect-a-cicd-variable)
|
||||
and [masked](../variables/index.md#mask-a-cicd-variable) variables for secret values.
|
||||
These variables can be accessed in pipeline jobs the same as variables defined in the
|
||||
configuration file.
|
||||
|
||||
For example, in a `Jenkinsfile`:
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Example Username/Password') {
|
||||
environment {
|
||||
AWS_ACCESS_KEY = credentials('aws-access-key')
|
||||
}
|
||||
steps {
|
||||
sh 'my-login-script.sh $AWS_ACCESS_KEY'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The equivalent GitLab CI/CD `.gitlab-ci.yml` file would be:
|
||||
|
||||
```yaml
|
||||
login-job:
|
||||
script:
|
||||
- my-login-script.sh $AWS_ACCESS_KEY
|
||||
```
|
||||
|
||||
Additionally, GitLab CI/CD makes [predefined variables](../variables/predefined_variables.md)
|
||||
available to every pipeline and job which contain values relevant to the pipeline and repository.
|
||||
|
||||
#### Expressions and conditionals
|
||||
|
||||
When a new pipeline starts, GitLab checks which jobs should run in that pipeline.
|
||||
You can configure jobs to run depending on factors like the status of variables,
|
||||
or the pipeline type.
|
||||
|
||||
For example, in a `Jenkinsfile`:
|
||||
|
||||
```groovy
|
||||
stage('deploy_staging') {
|
||||
agent { docker 'alpine:latest' }
|
||||
when {
|
||||
branch 'staging'
|
||||
}
|
||||
steps {
|
||||
echo "Deploying to staging"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the job only runs when the branch we are committing to is named `staging`.
|
||||
|
||||
The equivalent GitLab CI/CD `.gitlab-ci.yml` file would be:
|
||||
|
||||
```yaml
|
||||
deploy_staging:
|
||||
stage: deploy
|
||||
script:
|
||||
- echo "Deploy to staging server"
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == staging'
|
||||
```
|
||||
|
||||
#### Runners
|
||||
|
||||
Like Jenkins agents, GitLab runners are the hosts that run jobs. If you are using GitLab.com,
|
||||
you can use the [shared runner fleet](../runners/index.md) to run jobs without provisioning
|
||||
|
|
@ -99,233 +487,144 @@ Some key details about runners:
|
|||
for finer control, and associate runners with specific jobs. For example, you can use a tag for jobs that
|
||||
require dedicated, more powerful, or specific hardware.
|
||||
- GitLab has [autoscaling for runners](https://docs.gitlab.com/runner/configuration/autoscale.html).
|
||||
Use autoscaling to provision runners only when needed and scale down when not needed,
|
||||
similar to ephemeral agents in Jenkins.
|
||||
Use autoscaling to provision runners only when needed and scale down when not needed.
|
||||
|
||||
## YAML configuration file
|
||||
For example, in a `Jenkinsfile`:
|
||||
|
||||
GitLab pipeline configuration files use the [YAML](https://yaml.org/) format instead of
|
||||
the [Groovy](https://groovy-lang.org/) format that Jenkins uses.
|
||||
|
||||
Using YAML is a strength of GitLab CI/CD, as it is a simple format to understand
|
||||
and start using. For example, a small configuration file with two jobs and some
|
||||
shared configuration in a hidden job:
|
||||
|
||||
```yaml
|
||||
.test-config:
|
||||
tags:
|
||||
- docker-runners
|
||||
stage: test
|
||||
|
||||
test-job:
|
||||
extends:
|
||||
- .test-config
|
||||
script:
|
||||
- bundle exec rake rspec
|
||||
|
||||
lint-job:
|
||||
extends:
|
||||
- .test-config
|
||||
script:
|
||||
- yarn run prettier
|
||||
```groovy
|
||||
pipeline {
|
||||
agent none
|
||||
stages {
|
||||
stage('Linux') {
|
||||
agent {
|
||||
label 'linux'
|
||||
}
|
||||
steps {
|
||||
echo "Hello, $USER"
|
||||
}
|
||||
}
|
||||
stage('Windows') {
|
||||
agent {
|
||||
label 'windows'
|
||||
}
|
||||
steps {
|
||||
echo "Hello, %USERNAME%"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The commands to run in jobs are added with the [`script` keyword](../yaml/index.md#script).
|
||||
- The [`extends` keyword](../yaml/index.md#extends) reduces duplication in the configuration
|
||||
by adding the same `tags` and `stage` configuration defined in `.test-config` to both jobs.
|
||||
|
||||
### Artifacts
|
||||
|
||||
In GitLab, any job can use the [`artifacts` keyword](../yaml/index.md#artifacts)
|
||||
to define a set of [artifacts](../jobs/job_artifacts.md) to be stored when a job completes.
|
||||
Artifacts are files that can be used in later jobs, for example for testing or deployment.
|
||||
|
||||
For example:
|
||||
The equivalent GitLab CI/CD `.gitlab-ci.yml` file would be:
|
||||
|
||||
```yaml
|
||||
pdf:
|
||||
script: xelatex mycv.tex
|
||||
linux_job:
|
||||
stage: build
|
||||
tags:
|
||||
- linux
|
||||
script:
|
||||
- echo "Hello, $USER"
|
||||
|
||||
windows_job:
|
||||
stage: build
|
||||
tags:
|
||||
- windows
|
||||
script:
|
||||
- echo "Hello, %USERNAME%"
|
||||
```
|
||||
|
||||
#### Artifacts
|
||||
|
||||
In GitLab, any job can use the [`artifacts`](../../ci/yaml/index.md#artifacts) keyword to define a set of artifacts to
|
||||
be stored when a job completes. [Artifacts](../../ci/jobs/job_artifacts.md) are files that can be used in later jobs,
|
||||
for example for testing or deployment.
|
||||
|
||||
For example, in a `Jenkinsfile`:
|
||||
|
||||
```groovy
|
||||
stages {
|
||||
stage('Generate Cat') {
|
||||
steps {
|
||||
sh 'touch cat.txt'
|
||||
sh 'echo "meow" > cat.txt'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
archiveArtifacts artifacts: 'cat.txt'
|
||||
onlyIfSuccessful: true
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Use Cat') {
|
||||
steps {
|
||||
sh 'cat cat.txt'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The equivalent GitLab CI/CD `.gitlab-ci.yml` file would be:
|
||||
|
||||
```yaml
|
||||
stages:
|
||||
- generate
|
||||
- use
|
||||
|
||||
generate_cat:
|
||||
stage: generate
|
||||
script:
|
||||
- touch cat.txt
|
||||
- echo "meow" > cat.txt
|
||||
artifacts:
|
||||
paths:
|
||||
- mycv.pdf
|
||||
- output/
|
||||
- cat.txt
|
||||
expire_in: 1 week
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `mycv.pdf` file and all the files in `output/` are stored and could be used
|
||||
in later jobs.
|
||||
- To save resources, the artifacts expire and are deleted after one week.
|
||||
|
||||
### Scanning features
|
||||
|
||||
You might have used plugins for things like code quality, security, or static application scanning
|
||||
in Jenkins. Tools like these are already available in GitLab and can be used in your
|
||||
pipeline.
|
||||
|
||||
GitLab features including [code quality](../testing/code_quality.md), [security scanning](../../user/application_security/index.md),
|
||||
[SAST](../../user/application_security/sast/index.md), and many others generate reports
|
||||
when they complete. These reports can be displayed in merge requests and pipeline details pages.
|
||||
|
||||
### Templates
|
||||
|
||||
For organizations with many CI/CD pipelines, you can use project templates to configure
|
||||
custom CI/CD configuration templates and reuse them across projects.
|
||||
|
||||
Group maintainers can configure a group to use as the source for [custom project templates](../../administration/custom_project_templates.md).
|
||||
These templates can be used by all projects in the group.
|
||||
|
||||
An instance administrator can set a group as the source for [instance project templates](../../user/group/custom_project_templates.md),
|
||||
which can be used by all projects in that instance.
|
||||
|
||||
## Convert a declarative Jenkinsfile
|
||||
|
||||
A declarative Jenkinsfile contains "Sections" and "Directives" which are used to control the behavior of your
|
||||
pipelines. Equivalents for all of these exist in GitLab, which we've documented below.
|
||||
|
||||
This section is based on the [Jenkinsfile syntax documentation](https://www.jenkins.io/doc/book/pipeline/syntax/)
|
||||
and is meant to be a mapping of concepts there to concepts in GitLab.
|
||||
|
||||
### Sections
|
||||
|
||||
#### `agent`
|
||||
|
||||
The agent section is used to define how a pipeline executes. For GitLab, we use [runners](../runners/index.md)
|
||||
to provide this capability. You can configure your own runners in Kubernetes or on any host. You can also take advantage
|
||||
of our shared runner fleet (the shared runner fleet is only available for GitLab.com users).
|
||||
We also support using [tags](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) to direct different jobs
|
||||
to different runners (execution agents).
|
||||
|
||||
The `agent` section also allows you to define which Docker images should be used for execution, for which we use
|
||||
the [`image`](../yaml/index.md#image) keyword. The `image` can be set on a single job or at the top level, in which
|
||||
case it applies to all jobs in the pipeline:
|
||||
|
||||
```yaml
|
||||
my_job:
|
||||
image: alpine
|
||||
```
|
||||
|
||||
#### `post`
|
||||
|
||||
The `post` section defines the actions that should be performed at the end of the pipeline. GitLab also supports
|
||||
this through the use of stages. You can define your stages as follows, and any jobs assigned to the `before_pipeline`
|
||||
or `after_pipeline` stages run as expected. You can call these stages anything you like:
|
||||
|
||||
```yaml
|
||||
stages:
|
||||
- before_pipeline
|
||||
- build
|
||||
- test
|
||||
- deploy
|
||||
- after_pipeline
|
||||
```
|
||||
|
||||
Setting a step to be performed before and after any job can be done via the
|
||||
[`before_script`](../yaml/index.md#before_script) and [`after_script`](../yaml/index.md#after_script) keywords:
|
||||
|
||||
```yaml
|
||||
default:
|
||||
before_script:
|
||||
- echo "I run before any jobs starts in the entire pipeline, and can be responsible for setting up the environment."
|
||||
```
|
||||
|
||||
#### `stages`
|
||||
|
||||
GitLab CI/CD also lets you define stages, but is a little bit more free-form to configure. The GitLab [`stages` keyword](../yaml/index.md#stages)
|
||||
is a top level setting that enumerates the list of stages. You are not required to nest individual jobs underneath
|
||||
the `stages` section. Any job defined in the `.gitlab-ci.yml` can be made a part of any stage through use of the
|
||||
[`stage` keyword](../yaml/index.md#stage).
|
||||
|
||||
Unless otherwise specified, every pipeline is instantiated with a `build`, `test`, and `deploy` stage
|
||||
which are run in that order. Jobs that have no `stage` defined are placed by default in the `test` stage.
|
||||
Of course, each job that refers to a stage must refer to a stage that exists in the pipeline configuration.
|
||||
|
||||
```yaml
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- deploy
|
||||
|
||||
my_job:
|
||||
stage: build
|
||||
```
|
||||
|
||||
#### `steps`
|
||||
|
||||
The `steps` section is equivalent to the [`script` section](../yaml/index.md#script) of an individual job. The `steps` section is a YAML array
|
||||
with each line representing an individual command to be run:
|
||||
|
||||
```yaml
|
||||
my_job:
|
||||
use_cat:
|
||||
stage: use
|
||||
script:
|
||||
- echo "hello! the current time is:"
|
||||
- time
|
||||
- cat cat.txt
|
||||
artifacts:
|
||||
paths:
|
||||
- cat.txt
|
||||
```
|
||||
|
||||
### Directives
|
||||
#### Caching
|
||||
|
||||
#### `environment`
|
||||
A [cache](../../ci/caching/index.md) is created when a job downloads one or more files and
|
||||
saves them for faster access in the future. Subsequent jobs that use the same cache don't have to download the files again,
|
||||
so they execute more quickly. The cache is stored on the runner and uploaded to S3 if
|
||||
[distributed cache is enabled](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching).
|
||||
Jenkins core does not provide caching.
|
||||
|
||||
In GitLab, we use the [`variables` keyword](../yaml/index.md#variables) to define different variables at runtime.
|
||||
These can also be set up through the GitLab UI, under CI/CD settings. See also our [general documentation on variables](../variables/index.md),
|
||||
including the section on [protected variables](../variables/index.md#protect-a-cicd-variable). This can be used
|
||||
to limit access to certain variables to certain environments or runners:
|
||||
For example, in a `.gitlab-ci.yml` file:
|
||||
|
||||
```yaml
|
||||
variables:
|
||||
POSTGRES_USER: user
|
||||
POSTGRES_PASSWORD: testing_password
|
||||
```
|
||||
|
||||
#### `options`
|
||||
|
||||
Here, options for different things exist associated with the object in question itself. For example, options related
|
||||
to jobs are defined in relation to the job itself. If you're looking for a certain option, you should be able to find
|
||||
where it's located by searching our [complete configuration reference](../yaml/index.md) page.
|
||||
|
||||
#### `parameters`
|
||||
|
||||
GitLab does not require you to define which variables you want to be available when starting a manual job. A user
|
||||
can provide any variables they like.
|
||||
|
||||
#### `triggers` / `cron`
|
||||
|
||||
Because GitLab is integrated tightly with Git, SCM polling options for triggers are not needed. We support a
|
||||
[syntax for scheduling pipelines](../pipelines/schedules.md).
|
||||
|
||||
#### `tools`
|
||||
|
||||
GitLab does not support a separate `tools` directive. Our best-practice recommendation is to use pre-built
|
||||
container images. These images can be cached and can be built to already contain the tools you need for your pipelines. Pipelines can
|
||||
be set up to automatically build these images as needed and deploy them to the [container registry](../../user/packages/container_registry/index.md).
|
||||
|
||||
If you don't use container images with Docker or Kubernetes, but use the `shell` executor on your own system,
|
||||
you must set up your environment. You can set up the environment in advance, or as part of the jobs
|
||||
with a `before_script` action that handles this for you.
|
||||
|
||||
#### `input`
|
||||
|
||||
Similar to the `parameters` keyword, this is not needed because a manual job can always be provided runtime
|
||||
variable entry.
|
||||
|
||||
#### `when`
|
||||
|
||||
GitLab does support a [`when` keyword](../yaml/index.md#when) which is used to indicate when a job should be
|
||||
run in case of (or despite) failure. Most of the logic for controlling pipelines can be found in
|
||||
our very powerful [`rules` system](../yaml/index.md#rules):
|
||||
|
||||
```yaml
|
||||
my_job:
|
||||
cache-job:
|
||||
script:
|
||||
- echo
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
- echo "This job uses a cache."
|
||||
cache:
|
||||
key: binaries-cache-$CI_COMMIT_REF_SLUG
|
||||
paths:
|
||||
- binaries/
|
||||
```
|
||||
|
||||
## Secrets Management
|
||||
### Security Scanning features
|
||||
|
||||
You might have used plugins for things like code quality, security, or static application scanning in Jenkins.
|
||||
GitLab provides [security scanners](../../user/application_security/index.md) out-of-the-box to detect
|
||||
vulnerabilities in all parts of the SDLC. You can add these plugins in GitLab using templates, for example to add
|
||||
SAST scanning to your pipeline, add the following to your `.gitlab-ci.yml`:
|
||||
|
||||
```yaml
|
||||
include:
|
||||
- template: Security/SAST.gitlab-ci.yml
|
||||
```
|
||||
|
||||
You can customize the behavior of security scanners by using CI/CD variables, for example
|
||||
with the [SAST scanners](../../user/application_security/sast/index.md#available-cicd-variables).
|
||||
|
||||
### Secrets Management
|
||||
|
||||
Privileged information, often referred to as "secrets", is sensitive information
|
||||
or credentials you need in your CI/CD workflow. You might use secrets to unlock protected resources
|
||||
|
|
@ -358,15 +657,59 @@ only be done in [the project, group, or instance settings](../variables/index.md
|
|||
Review the [security guidelines](../variables/index.md#cicd-variable-security) to improve
|
||||
the safety of your CI/CD variables.
|
||||
|
||||
## Additional resources
|
||||
## Planning and Performing a Migration
|
||||
|
||||
The following list of recommended steps was created after observing organizations
|
||||
that were able to quickly complete this migration.
|
||||
|
||||
### Create a Migration Plan
|
||||
|
||||
Before starting a migration you should create a [migration plan](plan_a_migration.md) to make preparations for the migration. For a migration from Jenkins, ask yourself the following questions in preparation:
|
||||
|
||||
- What plugins are used by jobs in Jenkins today?
|
||||
- Do you know what these plugins do exactly?
|
||||
- Do any plugins wrap a common build tool? For example, Maven, Gradle, or NPM?
|
||||
- What is installed on the Jenkins agents?
|
||||
- Are there any shared libraries in use?
|
||||
- How are you authenticating from Jenkins? Are you using SSH keys, API tokens, or other secrets?
|
||||
- Are there other projects that you need to access from your pipeline?
|
||||
- Are there credentials in Jenkins to access outside services? For example Ansible Tower,
|
||||
Artifactory, or other Cloud Providers or deployment targets?
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before doing any migration work, you should first:
|
||||
|
||||
1. Get familiar with GitLab.
|
||||
- Read about the [key GitLab CI/CD features](../../ci/index.md).
|
||||
- Follow tutorials to create [your first GitLab pipeline](../quick_start/index.md) and [more complex pipelines](../quick_start/tutorial.md) that build, test, and deploys a static site.
|
||||
- Review the [`.gitlab-ci.yml` keyword reference](../yaml/index.md).
|
||||
1. Set up and configure GitLab.
|
||||
1. Test your GitLab instance.
|
||||
- Ensure [runners](../runners/index.md) are available, either by using shared GitLab.com runners or installing new runners.
|
||||
|
||||
### Migration Steps
|
||||
|
||||
1. Migrate projects from your SCM solution to GitLab.
|
||||
- (Recommended) You can use the available [importers](../../user/project/import/index.md)
|
||||
to automate mass imports from external SCM providers.
|
||||
- You can [import repositories by URL](../../user/project/import/repo_by_url.md).
|
||||
1. Create a `.gitlab-ci.yml` file in each project.
|
||||
1. Migrate Jenkins configuration to GitLab CI/CD jobs and configure them to show results directly in merge requests.
|
||||
1. Migrate deployment jobs by using [cloud deployment templates](../cloud_deployment/index.md),
|
||||
[environments](../environments/index.md), and the [GitLab agent for Kubernetes](../../user/clusters/agent/index.md).
|
||||
1. Check if any CI/CD configuration can be reused across different projects, then create
|
||||
and share CI/CD templates.
|
||||
1. Check the [pipeline efficiency documentation](../pipelines/pipeline_efficiency.md)
|
||||
to learn how to make your GitLab CI/CD pipelines faster and more efficient.
|
||||
|
||||
### Additional Resources
|
||||
|
||||
- You can use the [JenkinsFile Wrapper](https://gitlab.com/gitlab-org/jfr-container-builder/)
|
||||
to run a complete Jenkins instance inside of a GitLab CI/CD job, including plugins. Use this tool to
|
||||
help ease the transition to GitLab CI/CD, by delaying the migration of less urgent pipelines.
|
||||
to run a complete Jenkins instance inside of a GitLab CI/CD job, including plugins. Use this tool to help ease the transition to GitLab CI/CD, by delaying the migration of less urgent pipelines.
|
||||
|
||||
NOTE:
|
||||
The JenkinsFile Wrapper is not packaged with GitLab and falls outside of the scope of support.
|
||||
For more information, see the [Statement of Support](https://about.gitlab.com/support/statement-of-support/).
|
||||
- If your tooling outputs packages that you want to make accessible, you can store them
|
||||
in a [package registry](../../user/packages/index.md).
|
||||
- Use [review Apps](../review_apps/index.md) to preview changes before merging them.
|
||||
|
||||
If you have questions that are not answered here, the [GitLab community forum](https://forum.gitlab.com/) can be a great resource.
|
||||
|
|
|
|||
|
|
@ -55,21 +55,6 @@ the migration requirements:
|
|||
- How do you deploy your code?
|
||||
- Where do you deploy your code?
|
||||
|
||||
### Jenkins
|
||||
|
||||
If you are [migrating from Jenkins](jenkins.md), these additional questions can help with planning
|
||||
the migration:
|
||||
|
||||
- What plugins are used by jobs in Jenkins today?
|
||||
- Do you know what these plugins do exactly?
|
||||
- Do any plugin wrap a common build tool? For example, Maven, Gradle, or NPM?
|
||||
- What is installed on the Jenkins agents?
|
||||
- Are there any shared libraries in use?
|
||||
- How are you authenticating from Jenkins? Are you using SSH keys, API tokens, or other secrets?
|
||||
- Are there other projects that you need to access from your pipeline?
|
||||
- Are there credentials in Jenkins to access outside services? For example Ansible Tower,
|
||||
Artifactory, or other Cloud Providers or deployment targets?
|
||||
|
||||
## Related topics
|
||||
|
||||
- How to migrate Atlassian Bamboo Server's CI/CD infrastructure to GitLab CI/CD, [part one](https://about.gitlab.com/blog/2022/07/06/migration-from-atlassian-bamboo-server-to-gitlab-ci/)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ bin/rails g gitlab:analytics:internal_events \
|
|||
--mr=https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121544
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `time_frames`: Valid options are `7d` and `28d` if you provide a `unique` value and `all` for metrics without `unique`. We are working to make `7d` and `28d` work for metrics with `all` time frame in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/411264).
|
||||
- `unique`: Valid options are `user.id`, `project.id`, and `namespace.id`, as they are logged as part of the standard context. We [are actively working](https://gitlab.com/gitlab-org/gitlab/-/issues/411255) on a way to define uniqueness on arbitrary properties sent with the event, such as `merge_request.id`.
|
||||
|
||||
## Trigger events
|
||||
|
||||
Triggering an event and thereby updating a metric is slightly different on backend and frontend. Please refer to the relevant section below.
|
||||
|
|
@ -135,7 +140,3 @@ Sometimes we want to send internal events when the component is rendered or load
|
|||
= render Pajamas::ButtonComponent.new(button_options: { data: { event_tracking_load: 'true', event_tracking: 'i_devops' } }) do
|
||||
= _("New project")
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
The only values we allow for `unique` are `user.id`, `project.id`, and `namespace.id`, as they are logged as part of the standard context. We currently don't have anywhere to put a value like `merge_request.id`. That will change with self-describing events.
|
||||
|
|
|
|||
|
|
@ -293,20 +293,20 @@ In GitLab 12.1 and later, only PostgreSQL is supported. In GitLab 16.0 and later
|
|||
|
||||
1. Install the database packages.
|
||||
|
||||
For Ubuntu 20.04 and later:
|
||||
For Ubuntu 22.04 and later:
|
||||
|
||||
```shell
|
||||
sudo apt install -y postgresql postgresql-client libpq-dev postgresql-contrib
|
||||
```
|
||||
|
||||
For Ubuntu 18.04 and earlier, the available PostgreSQL doesn't meet the minimum
|
||||
For Ubuntu 20.04 and earlier, the available PostgreSQL doesn't meet the minimum
|
||||
version requirement. You must add PostgreSQL's repository:
|
||||
|
||||
```shell
|
||||
sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||
sudo apt update
|
||||
sudo apt -y install postgresql-12 postgresql-client-12 libpq-dev
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install postgresql-14
|
||||
```
|
||||
|
||||
1. Verify the PostgreSQL version you have is supported by the version of GitLab you're
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Dependency Scanning **(ULTIMATE ALL)**
|
||||
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an interactive reading and how-to demo of this Dependency Scanning doc, see [How to use dependency scanning tutorial hands-on GitLab Application Security part 3](https://youtu.be/ii05cMbJ4xQ?feature=shared)
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an interactive reading and how-to demo playlist, see [Get Started With GitLab Application Security Playlist](https://www.youtube.com/playlist?list=PL05JrBw4t0KrUrjDoefSkgZLx5aJYFaF9)
|
||||
|
||||
Dependency Scanning analyzes your application's dependencies for known vulnerabilities. All
|
||||
dependencies are scanned, including transitive dependencies, also known as nested dependencies.
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an overview, see [Adopting GitLab application security](https://www.youtube.com/watch?v=5QlxkiKR04k).
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an interactive reading and how-to demo playlist, see [Get Started With GitLab Application Security Playlist](https://www.youtube.com/playlist?list=PL05JrBw4t0KrUrjDoefSkgZLx5aJYFaF9)
|
||||
|
||||
The following steps help you get the most from GitLab application security tools. These steps are a recommended order of operations. You can choose to implement capabilities in a different order or omit features that do not apply to your specific needs.
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
> `secret_detection_default_branch` and `secret_detection` were consolidated into one job,
|
||||
> `secret_detection`.
|
||||
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an interactive reading and how-to demo of this Secret Detection doc, see [How to enable secret detection in GitLab Application Security Part 1/2](https://youtu.be/dbMxeO6nJCE?feature=shared) and [How to enable secret detection in GitLab Application Security Part 2/2](https://youtu.be/VL-_hdiTazo?feature=shared)
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an interactive reading and how-to demo playlist, see [Get Started With GitLab Application Security Playlist](https://www.youtube.com/playlist?list=PL05JrBw4t0KrUrjDoefSkgZLx5aJYFaF9)
|
||||
|
||||
People sometimes accidentally commit secrets like keys or API tokens to Git repositories.
|
||||
After a sensitive value is pushed to a remote repository, anyone with access to the repository can impersonate the authorized user of the secret for malicious purposes.
|
||||
Most organizations require exposed secrets to be revoked and replaced to address this risk.
|
||||
|
|
|
|||
|
|
@ -134,9 +134,11 @@ can be added to the group.
|
|||
|
||||
The most popular public email domains cannot be restricted, such as:
|
||||
|
||||
- `gmail.com`, `yahoo.com`, `aol.com`, `icloud.com`
|
||||
- `hotmail.com`, `hotmail.co.uk`, `hotmail.fr`
|
||||
- `msn.com`, `live.com`, `outlook.com`
|
||||
- `aol.com`, `gmail.com`, `hotmail.co.uk`, `hotmail.com`,
|
||||
- `hotmail.fr`, `icloud.com`, `live.com`, `mail.com`,
|
||||
- `me.com`, `msn.com`, `outlook.com`,
|
||||
- `proton.me`, `protonmail.com`, `tutanota.com`,
|
||||
- `yahoo.com`, `yandex.com`, `zohomail.com`
|
||||
|
||||
When you share a group, both the source and target namespaces must allow the domains of the members' email addresses.
|
||||
|
||||
|
|
|
|||
|
|
@ -61,13 +61,18 @@ When deleting users, you can either:
|
|||
- Delete the user and their contributions, including:
|
||||
- Abuse reports.
|
||||
- Emoji reactions.
|
||||
- Epics.
|
||||
- Groups of which the user is the only user with the Owner role.
|
||||
- Personal access tokens.
|
||||
- Epics.
|
||||
- Issues.
|
||||
- Merge requests.
|
||||
- Notes and comments.
|
||||
- Personal access tokens.
|
||||
- Snippets.
|
||||
- [Notes and comments](../../../api/notes.md)
|
||||
on other users' [commits](../../project/repository/index.md#commit-changes-to-a-repository),
|
||||
[epics](../../group/epics/index.md),
|
||||
[issues](../../project/issues/index.md),
|
||||
[merge requests](../../project/merge_requests/index.md)
|
||||
and [snippets](../../snippets.md).
|
||||
|
||||
An alternative to deleting is [blocking a user](../../../administration/moderate_users.md#block-a-user).
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ To use one or more custom domain names:
|
|||
- Add a [custom **root domain** or a **subdomain**](#set-up-a-custom-domain).
|
||||
- Add [SSL/TLS certification](#adding-an-ssltls-certificate-to-pages).
|
||||
|
||||
WARNING:
|
||||
You cannot verify the [most popular public email domains](../../../../user/group/access_and_permissions.md#restrict-group-access-by-domain).
|
||||
|
||||
## Set up a custom domain
|
||||
|
||||
To set up Pages with a custom domain name, read the requirements and steps below.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ module Backup
|
|||
sslcompression: 'PGSSLCOMPRESSION'
|
||||
}.freeze
|
||||
|
||||
OVERRIDE_PREFIX = "GITLAB_BACKUP_"
|
||||
|
||||
attr_reader :config
|
||||
|
||||
def initialize(name)
|
||||
|
|
@ -35,7 +37,7 @@ module Backup
|
|||
|
||||
original_config = source_model.connection_db_config.configuration_hash.dup
|
||||
|
||||
@config = config_for_backup(original_config)
|
||||
@config = config_for_backup(name, original_config)
|
||||
|
||||
@model.establish_connection(
|
||||
ActiveRecord::DatabaseConfigurations::HashConfig.new(
|
||||
|
|
@ -56,7 +58,7 @@ module Backup
|
|||
self.class.const_set(klass_name, Class.new(ApplicationRecord))
|
||||
end
|
||||
|
||||
def config_for_backup(config)
|
||||
def config_for_backup(name, config)
|
||||
db_config = {
|
||||
activerecord: config,
|
||||
pg_env: {}
|
||||
|
|
@ -65,8 +67,9 @@ module Backup
|
|||
# This enables the use of different PostgreSQL settings in
|
||||
# case PgBouncer is used. PgBouncer clears the search path,
|
||||
# which wreaks havoc on Rails if connections are reused.
|
||||
override = "GITLAB_BACKUP_#{arg}"
|
||||
val = ENV[override].presence || config[opt].to_s.presence
|
||||
override_all = "#{OVERRIDE_PREFIX}#{arg}"
|
||||
override_db = "#{OVERRIDE_PREFIX}#{name.upcase}_#{arg}"
|
||||
val = ENV[override_db].presence || ENV[override_all].presence || config[opt].to_s.presence
|
||||
|
||||
next unless val
|
||||
|
||||
|
|
|
|||
|
|
@ -32760,6 +32760,9 @@ msgstr ""
|
|||
msgid "Only SSH"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only SSH Certificates"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only accessible by %{membersPageLinkStart}project members%{membersPageLinkEnd}. Membership must be explicitly granted to each user."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -54473,6 +54476,9 @@ msgstr ""
|
|||
msgid "You cannot set yourself to awaiting"
|
||||
msgstr ""
|
||||
|
||||
msgid "You cannot verify %{value} because it is a popular public email domain."
|
||||
msgstr ""
|
||||
|
||||
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ module QA
|
|||
click_element(:import_project_button)
|
||||
|
||||
wait_until(reload: false) do
|
||||
has_notice?("The project was successfully imported.") || has_element?(:project_name_content)
|
||||
has_notice?("The project was successfully imported.") || has_element?('project-name-content')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ module QA
|
|||
end
|
||||
|
||||
def has_file_explorer?
|
||||
page.has_css?('.explorer-folders-view', visible: true)
|
||||
page.has_css?('[aria-label="Files Explorer"]', visible: true)
|
||||
has_element?('div[aria-label="Files Explorer"]')
|
||||
end
|
||||
|
||||
def right_click_file_explorer
|
||||
page.find('.explorer-folders-view', visible: true).right_click
|
||||
has_element?('div.monaco-list-rows')
|
||||
find_element('div[aria-label="Files Explorer"]').right_click
|
||||
end
|
||||
|
||||
def open_file_from_explorer(file_name)
|
||||
|
|
@ -32,78 +32,69 @@ module QA
|
|||
within_element('.monaco-editor', &block)
|
||||
end
|
||||
|
||||
def has_new_folder_menu_item?
|
||||
page.has_css?('[aria-label="New Folder..."]', visible: true)
|
||||
def has_right_click_menu_item?
|
||||
has_element?('div.menu-item-check')
|
||||
end
|
||||
|
||||
def click_new_folder_menu_item
|
||||
page.find('[aria-label="New Folder..."]').click
|
||||
end
|
||||
|
||||
def enter_new_folder_text_input(name)
|
||||
page.find('.explorer-item-edited', visible: true)
|
||||
send_keys(name, :enter)
|
||||
end
|
||||
|
||||
def has_upload_menu_item?
|
||||
page.has_css?('.menu-item-check', visible: true)
|
||||
click_element('span[aria-label="New Folder..."]')
|
||||
end
|
||||
|
||||
def click_upload_menu_item
|
||||
page.find('[aria-label="Upload..."]', visible: true).click
|
||||
click_element('span[aria-label="Upload..."]')
|
||||
end
|
||||
|
||||
def enter_new_folder_text_input(name)
|
||||
find_element('input[type="text"]')
|
||||
send_keys(name, :enter)
|
||||
end
|
||||
|
||||
def enter_file_input(file)
|
||||
page.find('input[type="file"]', visible: false).send_keys(file)
|
||||
find_element('input[type="file"]', visible: false).send_keys(file)
|
||||
end
|
||||
|
||||
def has_commit_pending_tab?
|
||||
page.has_css?('.scm-viewlet-label', visible: true)
|
||||
has_element?('.scm-viewlet-label')
|
||||
end
|
||||
|
||||
def click_commit_pending_tab
|
||||
page.find('.scm-viewlet-label', visible: true).click
|
||||
click_element('.scm-viewlet-label', visible: true)
|
||||
end
|
||||
|
||||
def click_commit_tab
|
||||
page.find('a.codicon-source-control-view-icon', visible: true).click
|
||||
click_element('.codicon-source-control-view-icon')
|
||||
end
|
||||
|
||||
def has_commit_message_box?
|
||||
page.has_css?('div.view-lines.monaco-mouse-cursor-text', visible: true)
|
||||
has_element?('div[aria-label="Source Control Input"]')
|
||||
end
|
||||
|
||||
def enter_commit_message(message)
|
||||
page.find('div.view-lines.monaco-mouse-cursor-text', visible: true).send_keys(message)
|
||||
end
|
||||
|
||||
def click_commit_button
|
||||
page.find('a.monaco-text-button', visible: true).click
|
||||
end
|
||||
|
||||
def has_notification_box?
|
||||
page.has_css?('a.monaco-text-button', visible: true)
|
||||
end
|
||||
|
||||
def create_merge_request
|
||||
Support::Waiter.wait_until(max_duration: 10, retry_on_exception: true) do
|
||||
within_vscode_editor do
|
||||
page.find('.monaco-button[title="Create MR"]').click
|
||||
end
|
||||
within_element('div[aria-label="Source Control Input"]') do
|
||||
find_element('.view-line').click
|
||||
send_keys(message)
|
||||
end
|
||||
end
|
||||
|
||||
def click_commit_button
|
||||
click_element('div[aria-label="Commit to \'main\'"]')
|
||||
end
|
||||
|
||||
def has_notification_box?
|
||||
has_element?('.monaco-dialog-box')
|
||||
end
|
||||
|
||||
def click_new_branch
|
||||
page.find('.monaco-button[title="Create new branch"]').click
|
||||
click_element('.monaco-button[title="Create new branch"]')
|
||||
end
|
||||
|
||||
def has_branch_input_field?
|
||||
page.has_css?('.monaco-findInput', visible: true)
|
||||
has_element?('input[aria-label="input"]')
|
||||
end
|
||||
|
||||
def has_message?(content)
|
||||
within_vscode_editor do
|
||||
page.has_content?(content)
|
||||
has_text?(content)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -133,15 +124,14 @@ module QA
|
|||
|
||||
def create_new_folder(name)
|
||||
within_vscode_editor do
|
||||
right_click_file_explorer
|
||||
has_new_folder_menu_item?
|
||||
|
||||
# Use for stability, WebIDE inside an iframe is finnicky, webdriver sometimes moves too fast
|
||||
Support::Waiter.wait_until(max_duration: 20, retry_on_exception: true) do
|
||||
right_click_file_explorer
|
||||
has_right_click_menu_item?
|
||||
click_new_folder_menu_item
|
||||
# Verify New Folder button is triggered and textbox is waiting for input
|
||||
enter_new_folder_text_input(name)
|
||||
page.has_content?(name)
|
||||
has_text?(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -160,8 +150,8 @@ module QA
|
|||
end
|
||||
|
||||
has_commit_message_box?
|
||||
send_keys(message)
|
||||
page.has_content?(message)
|
||||
enter_commit_message(message)
|
||||
has_text?(message)
|
||||
click_commit_button
|
||||
has_notification_box?
|
||||
end
|
||||
|
|
@ -176,8 +166,14 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
def create_merge_request
|
||||
within_vscode_editor do
|
||||
has_element?('div[title="GitLab Web IDE Extension (Extension)"]')
|
||||
click_element('.monaco-button[title="Create MR"]')
|
||||
end
|
||||
end
|
||||
|
||||
def upload_file(file_path)
|
||||
wait_for_ide_to_load
|
||||
within_vscode_editor do
|
||||
# VSCode eagerly removes the input[type='file'] from click on Upload.
|
||||
# We need to execute a script on the iframe to stub out the iframes body.removeChild to add it back in.
|
||||
|
|
@ -186,32 +182,40 @@ module QA
|
|||
# Use for stability, WebIDE inside an iframe is finnicky, webdriver sometimes moves too fast
|
||||
Support::Waiter.wait_until(max_duration: 20, retry_on_exception: true) do
|
||||
right_click_file_explorer
|
||||
has_upload_menu_item?
|
||||
has_right_click_menu_item?
|
||||
click_upload_menu_item
|
||||
enter_file_input(file_path)
|
||||
end
|
||||
# Wait for the file to be uploaded
|
||||
has_text?(file_path)
|
||||
end
|
||||
end
|
||||
|
||||
def add_file_content(prompt_data)
|
||||
click_inside_editor_frame
|
||||
within_file_editor do
|
||||
send_keys(:enter, :enter, prompt_data)
|
||||
within_vscode_editor do
|
||||
click_inside_editor_frame
|
||||
within_file_editor do
|
||||
send_keys(:enter, :enter, prompt_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def verify_prompt_appears_and_accept(pattern)
|
||||
within_file_editor do
|
||||
Support::Waiter.wait_until(max_duration: 30) do
|
||||
page.text.match?(pattern)
|
||||
within_vscode_editor do
|
||||
within_file_editor do
|
||||
Support::Waiter.wait_until(max_duration: 30) do
|
||||
page.text.match?(pattern)
|
||||
end
|
||||
send_keys(:tab)
|
||||
end
|
||||
send_keys(:tab)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_prompt(pattern)
|
||||
within_file_editor do
|
||||
page.text.match?(pattern)
|
||||
within_vscode_editor do
|
||||
within_file_editor do
|
||||
page.text.match?(pattern)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ module QA
|
|||
type: :flaky
|
||||
} do
|
||||
describe 'Add a directory in Web IDE' do
|
||||
let(:project) { create(:project, :with_readme, name: 'add-directory-project') }
|
||||
let(:project) { create(:project, :with_readme, name: 'webide-add-directory-project') }
|
||||
|
||||
before do
|
||||
Flow::Login.sign_in
|
||||
|
|
@ -24,14 +24,15 @@ module QA
|
|||
])
|
||||
|
||||
project.visit!
|
||||
Page::Project::Show.perform(&:open_web_ide!)
|
||||
Page::Project::WebIDE::VSCode.perform(&:wait_for_ide_to_load)
|
||||
end
|
||||
|
||||
it 'throws an error', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386760' do
|
||||
Page::Project::Show.perform(&:open_web_ide!)
|
||||
Page::Project::WebIDE::VSCode.perform do |ide|
|
||||
ide.wait_for_ide_to_load
|
||||
ide.create_new_folder(directory_name)
|
||||
ide.has_message?('A file or folder first_directory already exists at this location.')
|
||||
|
||||
expect(ide).to have_message('A file or folder first_directory already exists at this location.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -41,15 +42,16 @@ module QA
|
|||
|
||||
before do
|
||||
Page::Project::Show.perform(&:open_web_ide!)
|
||||
Page::Project::WebIDE::VSCode.perform(&:wait_for_ide_to_load)
|
||||
end
|
||||
|
||||
it 'shows successfully but not able to be committed',
|
||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386761' do
|
||||
Page::Project::WebIDE::VSCode.perform do |ide|
|
||||
ide.wait_for_ide_to_load
|
||||
ide.create_new_folder(directory_name)
|
||||
ide.commit_toggle(directory_name)
|
||||
ide.has_message?('No changes found. Not able to commit.')
|
||||
|
||||
expect(ide).to have_message('No changes found. Not able to commit.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,38 +9,42 @@ module QA
|
|||
} do
|
||||
describe 'Upload a file in Web IDE' do
|
||||
let(:file_path) { File.absolute_path(File.join('qa', 'fixtures', 'web_ide', file_name)) }
|
||||
let(:project) { create(:project, :with_readme, name: 'upload-file-project') }
|
||||
let(:project) { create(:project, :with_readme, name: 'webide-upload-file-project') }
|
||||
|
||||
before do
|
||||
Flow::Login.sign_in
|
||||
project.visit!
|
||||
Page::Project::Show.perform(&:open_web_ide!)
|
||||
Page::Project::WebIDE::VSCode.perform(&:wait_for_ide_to_load)
|
||||
end
|
||||
|
||||
context 'when a file with the same name already exists' do
|
||||
let(:file_name) { 'README.md' }
|
||||
|
||||
it 'throws an error', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/390005' do
|
||||
Page::Project::Show.perform(&:open_web_ide!)
|
||||
Page::Project::WebIDE::VSCode.perform do |ide|
|
||||
ide.upload_file(file_path)
|
||||
ide.has_message?("A file or folder with the name 'README.md' already exists in the destination folder")
|
||||
|
||||
expect(ide)
|
||||
.to have_message("A file or folder with the name 'README.md' already exists in the destination folder")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'upload a file' do
|
||||
it "verifies it successfully uploads and commits to a MR" do
|
||||
Page::Project::Show.perform(&:open_web_ide!)
|
||||
Page::Project::WebIDE::VSCode.perform do |ide|
|
||||
ide.upload_file(file_path)
|
||||
ide.has_message?(file_name)
|
||||
ide.commit_and_push(file_name)
|
||||
ide.has_message?('Success! Your changes have been committed.')
|
||||
|
||||
expect(ide).to have_message('Success! Your changes have been committed.')
|
||||
|
||||
ide.create_merge_request
|
||||
end
|
||||
|
||||
# Opens the MR in new tab and verify the file is in the MR
|
||||
page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
|
||||
|
||||
Page::MergeRequest::Show.perform do |merge_request|
|
||||
expect(merge_request).to have_content(file_name)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ docker buildx build \
|
|||
--platform=${ARCH:-amd64} \
|
||||
--tag="${IMAGE}:${SHA_TAG}" \
|
||||
--tag="${IMAGE}:${BRANCH_TAG}" \
|
||||
--provenance=false \
|
||||
${OUTPUT_OPTION} \
|
||||
.
|
||||
|
||||
|
|
|
|||
|
|
@ -90,5 +90,6 @@ docker buildx build \
|
|||
--build-arg=QA_BUILD_TARGET="${QA_BUILD_TARGET}" \
|
||||
--file="${CI_PROJECT_DIR}/qa/Dockerfile" \
|
||||
--push \
|
||||
--provenance=false \
|
||||
${DESTINATIONS} \
|
||||
${CI_PROJECT_DIR}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe GroupsHelper do
|
||||
RSpec.describe GroupsHelper, feature_category: :groups_and_projects do
|
||||
include ApplicationHelper
|
||||
include AvatarsHelper
|
||||
|
||||
|
|
@ -97,23 +97,11 @@ RSpec.describe GroupsHelper do
|
|||
end
|
||||
end
|
||||
|
||||
context 'recursive' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
include_examples 'correct ancestor order'
|
||||
before do
|
||||
very_deep_nested_group.reload # make sure traversal_ids are reloaded
|
||||
end
|
||||
|
||||
context 'linear' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: true)
|
||||
|
||||
very_deep_nested_group.reload # make sure traversal_ids are reloaded
|
||||
end
|
||||
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
|
||||
it 'enqueues the elements in the breadcrumb schema list' do
|
||||
|
|
@ -269,21 +257,7 @@ RSpec.describe GroupsHelper do
|
|||
end
|
||||
end
|
||||
|
||||
context 'recursive' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
|
||||
context 'linear' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: true)
|
||||
end
|
||||
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -558,22 +532,24 @@ RSpec.describe GroupsHelper do
|
|||
end
|
||||
|
||||
describe "#enabled_git_access_protocol_options_for_group" do
|
||||
subject { helper.enabled_git_access_protocol_options_for_group }
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
subject { helper.enabled_git_access_protocol_options_for_group(group) }
|
||||
|
||||
before do
|
||||
expect(::Gitlab::CurrentSettings).to receive(:enabled_git_access_protocol).and_return(instance_setting)
|
||||
allow(::Gitlab::CurrentSettings).to receive(:enabled_git_access_protocol).and_return(instance_setting)
|
||||
end
|
||||
|
||||
context "instance setting is nil" do
|
||||
let(:instance_setting) { nil }
|
||||
|
||||
it { is_expected.to contain_exactly([_("Both SSH and HTTP(S)"), "all"], [_("Only SSH"), "ssh"], [_("Only HTTP(S)"), "http"]) }
|
||||
it { is_expected.to include([_("Both SSH and HTTP(S)"), "all"], [_("Only SSH"), "ssh"], [_("Only HTTP(S)"), "http"]) }
|
||||
end
|
||||
|
||||
context "instance setting is blank" do
|
||||
let(:instance_setting) { nil }
|
||||
let(:instance_setting) { '' }
|
||||
|
||||
it { is_expected.to contain_exactly([_("Both SSH and HTTP(S)"), "all"], [_("Only SSH"), "ssh"], [_("Only HTTP(S)"), "http"]) }
|
||||
it { is_expected.to include([_("Both SSH and HTTP(S)"), "all"], [_("Only SSH"), "ssh"], [_("Only HTTP(S)"), "http"]) }
|
||||
end
|
||||
|
||||
context "instance setting is ssh" do
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Backup::DatabaseModel, :reestablished_active_record_base, feature_category: :backup_restore do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let(:gitlab_database_name) { 'main' }
|
||||
|
||||
describe '#connection' do
|
||||
|
|
@ -30,7 +32,7 @@ RSpec.describe Backup::DatabaseModel, :reestablished_active_record_base, feature
|
|||
).to receive(:configuration_hash).and_return(application_config)
|
||||
end
|
||||
|
||||
context 'when no GITLAB_BACKUP_PG* variables are set' do
|
||||
shared_examples 'no configuration is overridden' do
|
||||
it 'ActiveRecord backup configuration is expected to equal application configuration' do
|
||||
expect(subject[:activerecord]).to eq(application_config)
|
||||
end
|
||||
|
|
@ -45,9 +47,23 @@ RSpec.describe Backup::DatabaseModel, :reestablished_active_record_base, feature
|
|||
end
|
||||
end
|
||||
|
||||
context 'when GITLAB_BACKUP_PG* variables are set' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
shared_examples 'environment variables override application configuration' do
|
||||
let(:active_record_key) { described_class::SUPPORTED_OVERRIDES.invert[pg_env] }
|
||||
|
||||
it 'ActiveRecord backup configuration overrides application configuration' do
|
||||
expect(subject[:activerecord]).to eq(application_config.merge(active_record_key => overridden_value))
|
||||
end
|
||||
|
||||
it 'PostgreSQL ENV overrides application configuration' do
|
||||
expect(subject[:pg_env]).to include({ pg_env => overridden_value })
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no GITLAB_BACKUP_PG* variables are set' do
|
||||
it_behaves_like 'no configuration is overridden'
|
||||
end
|
||||
|
||||
context 'when GITLAB_BACKUP_PG* variables are set' do
|
||||
where(:env_variable, :overridden_value) do
|
||||
'GITLAB_BACKUP_PGHOST' | 'test.invalid.'
|
||||
'GITLAB_BACKUP_PGUSER' | 'some_user'
|
||||
|
|
@ -63,18 +79,76 @@ RSpec.describe Backup::DatabaseModel, :reestablished_active_record_base, feature
|
|||
|
||||
with_them do
|
||||
let(:pg_env) { env_variable[/GITLAB_BACKUP_(\w+)/, 1] }
|
||||
let(:active_record_key) { described_class::SUPPORTED_OVERRIDES.invert[pg_env] }
|
||||
|
||||
before do
|
||||
stub_env(env_variable, overridden_value)
|
||||
end
|
||||
|
||||
it 'ActiveRecord backup configuration overrides application configuration' do
|
||||
expect(subject[:activerecord]).to eq(application_config.merge(active_record_key => overridden_value))
|
||||
it_behaves_like 'environment variables override application configuration'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when GITLAB_BACKUP_<DBNAME>_PG* variables are set' do
|
||||
context 'and environment variables are for the current database name' do
|
||||
where(:env_variable, :overridden_value) do
|
||||
'GITLAB_BACKUP_MAIN_PGHOST' | 'test.invalid.'
|
||||
'GITLAB_BACKUP_MAIN_PGUSER' | 'some_user'
|
||||
'GITLAB_BACKUP_MAIN_PGPORT' | '1543'
|
||||
'GITLAB_BACKUP_MAIN_PGPASSWORD' | 'secret'
|
||||
'GITLAB_BACKUP_MAIN_PGSSLMODE' | 'allow'
|
||||
'GITLAB_BACKUP_MAIN_PGSSLKEY' | 'some_key'
|
||||
'GITLAB_BACKUP_MAIN_PGSSLCERT' | '/path/to/cert'
|
||||
'GITLAB_BACKUP_MAIN_PGSSLROOTCERT' | '/path/to/root/cert'
|
||||
'GITLAB_BACKUP_MAIN_PGSSLCRL' | '/path/to/crl'
|
||||
'GITLAB_BACKUP_MAIN_PGSSLCOMPRESSION' | '1'
|
||||
end
|
||||
|
||||
it 'PostgreSQL ENV overrides application configuration' do
|
||||
expect(subject[:pg_env]).to include({ pg_env => overridden_value })
|
||||
with_them do
|
||||
let(:pg_env) { env_variable[/GITLAB_BACKUP_MAIN_(\w+)/, 1] }
|
||||
|
||||
before do
|
||||
stub_env(env_variable, overridden_value)
|
||||
end
|
||||
|
||||
it_behaves_like 'environment variables override application configuration'
|
||||
end
|
||||
end
|
||||
|
||||
context 'and environment variables are for another database' do
|
||||
where(:env_variable, :overridden_value) do
|
||||
'GITLAB_BACKUP_CI_PGHOST' | 'test.invalid.'
|
||||
'GITLAB_BACKUP_CI_PGUSER' | 'some_user'
|
||||
'GITLAB_BACKUP_CI_PGPORT' | '1543'
|
||||
'GITLAB_BACKUP_CI_PGPASSWORD' | 'secret'
|
||||
'GITLAB_BACKUP_CI_PGSSLMODE' | 'allow'
|
||||
'GITLAB_BACKUP_CI_PGSSLKEY' | 'some_key'
|
||||
'GITLAB_BACKUP_CI_PGSSLCERT' | '/path/to/cert'
|
||||
'GITLAB_BACKUP_CI_PGSSLROOTCERT' | '/path/to/root/cert'
|
||||
'GITLAB_BACKUP_CI_PGSSLCRL' | '/path/to/crl'
|
||||
'GITLAB_BACKUP_CI_PGSSLCOMPRESSION' | '1'
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:pg_env) { env_variable[/GITLAB_BACKUP_CI_(\w+)/, 1] }
|
||||
|
||||
before do
|
||||
stub_env(env_variable, overridden_value)
|
||||
end
|
||||
|
||||
it_behaves_like 'no configuration is overridden'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when both GITLAB_BACKUP_PGUSER and GITLAB_BACKUP_MAIN_PGUSER variable are present' do
|
||||
before do
|
||||
stub_env('GITLAB_BACKUP_PGUSER', 'generic_user')
|
||||
stub_env('GITLAB_BACKUP_MAIN_PGUSER', 'specfic_user')
|
||||
end
|
||||
|
||||
it 'prefers more specific GITLAB_BACKUP_MAIN_PGUSER' do
|
||||
config = subject
|
||||
expect(config.dig(:activerecord, :username)).to eq('specfic_user')
|
||||
expect(config.dig(:pg_env, 'PGUSER')).to eq('specfic_user')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Ci::Variables::Builder::Group do
|
||||
RSpec.describe Gitlab::Ci::Variables::Builder::Group, feature_category: :secrets_management do
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
let(:builder) { described_class.new(group) }
|
||||
|
|
@ -185,21 +185,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Group do
|
|||
end
|
||||
end
|
||||
|
||||
context 'recursive' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
|
||||
context 'linear' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: true)
|
||||
end
|
||||
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@ merge_requests:
|
|||
- created_environments
|
||||
- predictions
|
||||
- user_agent_detail
|
||||
- scan_result_policy_violations
|
||||
external_pull_requests:
|
||||
- project
|
||||
merge_request_diff:
|
||||
|
|
@ -823,6 +824,7 @@ project:
|
|||
- design_management_repository_state
|
||||
- compliance_standards_adherence
|
||||
- scan_result_policy_reads
|
||||
- scan_result_policy_violations
|
||||
- project_state
|
||||
- security_policy_bots
|
||||
- target_branch_rules
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Gitlab::ProtocolAccess do
|
||||
RSpec.describe Gitlab::ProtocolAccess, feature_category: :source_code_management do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
|
@ -10,25 +10,34 @@ RSpec.describe Gitlab::ProtocolAccess do
|
|||
|
||||
describe ".allowed?" do
|
||||
where(:protocol, :project, :admin_setting, :namespace_setting, :expected_result) do
|
||||
"web" | nil | nil | nil | true
|
||||
"ssh" | nil | nil | nil | true
|
||||
"http" | nil | nil | nil | true
|
||||
"ssh" | nil | "" | nil | true
|
||||
"http" | nil | "" | nil | true
|
||||
"ssh" | nil | "ssh" | nil | true
|
||||
"http" | nil | "http" | nil | true
|
||||
"ssh" | nil | "http" | nil | false
|
||||
"http" | nil | "ssh" | nil | false
|
||||
"ssh" | ref(:p1) | nil | "all" | true
|
||||
"http" | ref(:p1) | nil | "all" | true
|
||||
"ssh" | ref(:p1) | nil | "ssh" | true
|
||||
"http" | ref(:p1) | nil | "http" | true
|
||||
"ssh" | ref(:p1) | nil | "http" | false
|
||||
"http" | ref(:p1) | nil | "ssh" | false
|
||||
"ssh" | ref(:p1) | "" | "all" | true
|
||||
"http" | ref(:p1) | "" | "all" | true
|
||||
"ssh" | ref(:p1) | "ssh" | "ssh" | true
|
||||
"http" | ref(:p1) | "http" | "http" | true
|
||||
"web" | nil | nil | nil | true
|
||||
"ssh" | nil | nil | nil | true
|
||||
"http" | nil | nil | nil | true
|
||||
"ssh_certificates" | nil | nil | nil | true
|
||||
"ssh" | nil | "" | nil | true
|
||||
"http" | nil | "" | nil | true
|
||||
"ssh_certificates" | nil | "" | nil | true
|
||||
"ssh" | nil | "ssh" | nil | true
|
||||
"http" | nil | "http" | nil | true
|
||||
"ssh_certificates" | nil | "ssh_certificates" | nil | true
|
||||
"ssh" | nil | "http" | nil | false
|
||||
"http" | nil | "ssh" | nil | false
|
||||
"ssh_certificates" | nil | "ssh" | nil | false
|
||||
"ssh" | ref(:p1) | nil | "all" | true
|
||||
"http" | ref(:p1) | nil | "all" | true
|
||||
"ssh_certificates" | ref(:p1) | nil | "all" | true
|
||||
"ssh" | ref(:p1) | nil | "ssh" | true
|
||||
"http" | ref(:p1) | nil | "http" | true
|
||||
"ssh_certificates" | ref(:p1) | nil | "ssh_certificates" | true
|
||||
"ssh" | ref(:p1) | nil | "http" | false
|
||||
"http" | ref(:p1) | nil | "ssh" | false
|
||||
"ssh_certificates" | ref(:p1) | nil | "ssh" | false
|
||||
"ssh" | ref(:p1) | "" | "all" | true
|
||||
"http" | ref(:p1) | "" | "all" | true
|
||||
"ssh_certificates" | ref(:p1) | "" | "all" | true
|
||||
"ssh" | ref(:p1) | "ssh" | "ssh" | true
|
||||
"http" | ref(:p1) | "http" | "http" | true
|
||||
"ssh_certificates" | ref(:p1) | "ssh_certificates" | "ssh_certificates" | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe DeletePagesDomainWithReservedDomains, feature_category: :pages do
|
||||
describe 'migrates' do
|
||||
context 'when a reserved domain is provided' do
|
||||
it 'delete the domain' do
|
||||
table(:pages_domains).create!(domain: 'gmail.com', verification_code: 'gmail')
|
||||
expect { migrate! }.to change { PagesDomain.count }.by(-1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a reserved domain is provided with non standard case' do
|
||||
it 'delete the domain' do
|
||||
table(:pages_domains).create!(domain: 'AOl.com', verification_code: 'aol')
|
||||
expect { migrate! }.to change { PagesDomain.count }.by(-1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a non reserved domain is provided' do
|
||||
it 'does not delete the domain' do
|
||||
table(:pages_domains).create!(domain: 'example.com', verification_code: 'example')
|
||||
expect { migrate! }.not_to change { PagesDomain.count }
|
||||
expect(table(:pages_domains).find_by(domain: 'example.com')).not_to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -309,19 +309,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when use_traversal_ids* are enabled' do
|
||||
it_behaves_like '.belonging_to_parent_groups_of_project'
|
||||
end
|
||||
|
||||
context 'when use_traversal_ids* are disabled' do
|
||||
before do
|
||||
stub_feature_flags(
|
||||
use_traversal_ids: false
|
||||
)
|
||||
end
|
||||
|
||||
it_behaves_like '.belonging_to_parent_groups_of_project'
|
||||
end
|
||||
it_behaves_like '.belonging_to_parent_groups_of_project'
|
||||
|
||||
context 'with instance runners sharing enabled' do
|
||||
# group specific
|
||||
|
|
|
|||
|
|
@ -683,160 +683,126 @@ RSpec.describe Group, feature_category: :groups_and_projects do
|
|||
context 'traversal queries' do
|
||||
let_it_be(:group, reload: true) { create(:group, :nested) }
|
||||
|
||||
context 'recursive' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
it_behaves_like 'namespace traversal'
|
||||
|
||||
it_behaves_like 'namespace traversal'
|
||||
describe '#self_and_descendants' do
|
||||
it { expect(group.self_and_descendants.to_sql).to include 'traversal_ids @>' }
|
||||
end
|
||||
|
||||
describe '#self_and_descendants' do
|
||||
it { expect(group.self_and_descendants.to_sql).not_to include 'traversal_ids @>' }
|
||||
end
|
||||
describe '#self_and_descendant_ids' do
|
||||
it { expect(group.self_and_descendant_ids.to_sql).to include 'traversal_ids @>' }
|
||||
end
|
||||
|
||||
describe '#self_and_descendant_ids' do
|
||||
it { expect(group.self_and_descendant_ids.to_sql).not_to include 'traversal_ids @>' }
|
||||
end
|
||||
describe '#descendants' do
|
||||
it { expect(group.descendants.to_sql).to include 'traversal_ids @>' }
|
||||
end
|
||||
|
||||
describe '#descendants' do
|
||||
it { expect(group.descendants.to_sql).not_to include 'traversal_ids @>' }
|
||||
end
|
||||
describe '#self_and_hierarchy' do
|
||||
it { expect(group.self_and_hierarchy.to_sql).to include 'traversal_ids @>' }
|
||||
end
|
||||
|
||||
describe '#self_and_hierarchy' do
|
||||
it { expect(group.self_and_hierarchy.to_sql).not_to include 'traversal_ids @>' }
|
||||
end
|
||||
describe '#ancestors' do
|
||||
it { expect(group.ancestors.to_sql).to include "\"namespaces\".\"id\" = #{group.parent_id}" }
|
||||
|
||||
describe '#ancestors' do
|
||||
it { expect(group.ancestors.to_sql).not_to include 'traversal_ids <@' }
|
||||
end
|
||||
|
||||
describe '.shortest_traversal_ids_prefixes' do
|
||||
it { expect { described_class.shortest_traversal_ids_prefixes }.to raise_error /Feature not supported since the `:use_traversal_ids` is disabled/ }
|
||||
it 'hierarchy order' do
|
||||
expect(group.ancestors(hierarchy_order: :asc).to_sql).to include 'ORDER BY "depth" ASC'
|
||||
end
|
||||
end
|
||||
|
||||
context 'linear' do
|
||||
it_behaves_like 'namespace traversal'
|
||||
describe '#ancestors_upto' do
|
||||
it { expect(group.ancestors_upto.to_sql).to include "WITH ORDINALITY" }
|
||||
end
|
||||
|
||||
describe '#self_and_descendants' do
|
||||
it { expect(group.self_and_descendants.to_sql).to include 'traversal_ids @>' }
|
||||
end
|
||||
describe '.shortest_traversal_ids_prefixes' do
|
||||
subject { filter.shortest_traversal_ids_prefixes }
|
||||
|
||||
describe '#self_and_descendant_ids' do
|
||||
it { expect(group.self_and_descendant_ids.to_sql).to include 'traversal_ids @>' }
|
||||
end
|
||||
context 'for many top-level namespaces' do
|
||||
let!(:top_level_groups) { create_list(:group, 4) }
|
||||
|
||||
describe '#descendants' do
|
||||
it { expect(group.descendants.to_sql).to include 'traversal_ids @>' }
|
||||
end
|
||||
context 'when querying all groups' do
|
||||
let(:filter) { described_class.id_in(top_level_groups) }
|
||||
|
||||
describe '#self_and_hierarchy' do
|
||||
it { expect(group.self_and_hierarchy.to_sql).to include 'traversal_ids @>' }
|
||||
end
|
||||
|
||||
describe '#ancestors' do
|
||||
it { expect(group.ancestors.to_sql).to include "\"namespaces\".\"id\" = #{group.parent_id}" }
|
||||
|
||||
it 'hierarchy order' do
|
||||
expect(group.ancestors(hierarchy_order: :asc).to_sql).to include 'ORDER BY "depth" ASC'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#ancestors_upto' do
|
||||
it { expect(group.ancestors_upto.to_sql).to include "WITH ORDINALITY" }
|
||||
end
|
||||
|
||||
describe '.shortest_traversal_ids_prefixes' do
|
||||
subject { filter.shortest_traversal_ids_prefixes }
|
||||
|
||||
context 'for many top-level namespaces' do
|
||||
let!(:top_level_groups) { create_list(:group, 4) }
|
||||
|
||||
context 'when querying all groups' do
|
||||
let(:filter) { described_class.id_in(top_level_groups) }
|
||||
|
||||
it "returns all traversal_ids" do
|
||||
is_expected.to contain_exactly(
|
||||
*top_level_groups.map { |group| [group.id] }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when querying selected groups' do
|
||||
let(:filter) { described_class.id_in(top_level_groups.first) }
|
||||
|
||||
it "returns only a selected traversal_ids" do
|
||||
is_expected.to contain_exactly([top_level_groups.first.id])
|
||||
end
|
||||
it "returns all traversal_ids" do
|
||||
is_expected.to contain_exactly(
|
||||
*top_level_groups.map { |group| [group.id] }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for namespace hierarchy' do
|
||||
let!(:group_a) { create(:group) }
|
||||
let!(:group_a_sub_1) { create(:group, parent: group_a) }
|
||||
let!(:group_a_sub_2) { create(:group, parent: group_a) }
|
||||
let!(:group_b) { create(:group) }
|
||||
let!(:group_b_sub_1) { create(:group, parent: group_b) }
|
||||
let!(:group_c) { create(:group) }
|
||||
context 'when querying selected groups' do
|
||||
let(:filter) { described_class.id_in(top_level_groups.first) }
|
||||
|
||||
context 'when querying all groups' do
|
||||
let(:filter) { described_class.id_in([group_a, group_a_sub_1, group_a_sub_2, group_b, group_b_sub_1, group_c]) }
|
||||
|
||||
it 'returns only shortest prefixes of top-level groups' do
|
||||
is_expected.to contain_exactly(
|
||||
[group_a.id],
|
||||
[group_b.id],
|
||||
[group_c.id]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when sub-group is reparented' do
|
||||
let(:filter) { described_class.id_in([group_b_sub_1, group_c]) }
|
||||
|
||||
before do
|
||||
group_b_sub_1.update!(parent: group_c)
|
||||
end
|
||||
|
||||
it 'returns a proper shortest prefix of a new group' do
|
||||
is_expected.to contain_exactly(
|
||||
[group_c.id]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when querying sub-groups' do
|
||||
let(:filter) { described_class.id_in([group_a_sub_1, group_b_sub_1, group_c]) }
|
||||
|
||||
it 'returns sub-groups as they are shortest prefixes' do
|
||||
is_expected.to contain_exactly(
|
||||
[group_a.id, group_a_sub_1.id],
|
||||
[group_b.id, group_b_sub_1.id],
|
||||
[group_c.id]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when querying group and sub-group of this group' do
|
||||
let(:filter) { described_class.id_in([group_a, group_a_sub_1, group_c]) }
|
||||
|
||||
it 'returns parent groups as this contains all sub-groups' do
|
||||
is_expected.to contain_exactly(
|
||||
[group_a.id],
|
||||
[group_c.id]
|
||||
)
|
||||
end
|
||||
it "returns only a selected traversal_ids" do
|
||||
is_expected.to contain_exactly([top_level_groups.first.id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project namespace exists in the group' do
|
||||
let!(:project) { create(:project, group: group) }
|
||||
let!(:project_namespace) { project.project_namespace }
|
||||
context 'for namespace hierarchy' do
|
||||
let!(:group_a) { create(:group) }
|
||||
let!(:group_a_sub_1) { create(:group, parent: group_a) }
|
||||
let!(:group_a_sub_2) { create(:group, parent: group_a) }
|
||||
let!(:group_b) { create(:group) }
|
||||
let!(:group_b_sub_1) { create(:group, parent: group_b) }
|
||||
let!(:group_c) { create(:group) }
|
||||
|
||||
it 'filters out project namespace' do
|
||||
expect(group.descendants.find_by_id(project_namespace.id)).to be_nil
|
||||
context 'when querying all groups' do
|
||||
let(:filter) { described_class.id_in([group_a, group_a_sub_1, group_a_sub_2, group_b, group_b_sub_1, group_c]) }
|
||||
|
||||
it 'returns only shortest prefixes of top-level groups' do
|
||||
is_expected.to contain_exactly(
|
||||
[group_a.id],
|
||||
[group_b.id],
|
||||
[group_c.id]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when sub-group is reparented' do
|
||||
let(:filter) { described_class.id_in([group_b_sub_1, group_c]) }
|
||||
|
||||
before do
|
||||
group_b_sub_1.update!(parent: group_c)
|
||||
end
|
||||
|
||||
it 'returns a proper shortest prefix of a new group' do
|
||||
is_expected.to contain_exactly(
|
||||
[group_c.id]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when querying sub-groups' do
|
||||
let(:filter) { described_class.id_in([group_a_sub_1, group_b_sub_1, group_c]) }
|
||||
|
||||
it 'returns sub-groups as they are shortest prefixes' do
|
||||
is_expected.to contain_exactly(
|
||||
[group_a.id, group_a_sub_1.id],
|
||||
[group_b.id, group_b_sub_1.id],
|
||||
[group_c.id]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when querying group and sub-group of this group' do
|
||||
let(:filter) { described_class.id_in([group_a, group_a_sub_1, group_c]) }
|
||||
|
||||
it 'returns parent groups as this contains all sub-groups' do
|
||||
is_expected.to contain_exactly(
|
||||
[group_a.id],
|
||||
[group_c.id]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project namespace exists in the group' do
|
||||
let!(:project) { create(:project, group: group) }
|
||||
let!(:project_namespace) { project.project_namespace }
|
||||
|
||||
it 'filters out project namespace' do
|
||||
expect(group.descendants.find_by_id(project_namespace.id)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1683,6 +1649,14 @@ RSpec.describe Group, feature_category: :groups_and_projects do
|
|||
it 'returns correct access level' do
|
||||
expect(group.max_member_access_for_user(group_user)).to eq(Gitlab::Access::OWNER)
|
||||
end
|
||||
|
||||
context 'when user is not active' do
|
||||
let_it_be(:group_user) { create(:user, :deactivated) }
|
||||
|
||||
it 'returns NO_ACCESS' do
|
||||
expect(group.max_member_access_for_user(group_user)).to eq(Gitlab::Access::NO_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is nil' do
|
||||
|
|
|
|||
|
|
@ -598,23 +598,7 @@ RSpec.describe Integration, feature_category: :integrations do
|
|||
end
|
||||
end
|
||||
|
||||
context 'recursive' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
|
||||
context 'linear' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: true)
|
||||
|
||||
sub_subgroup.reload # make sure traversal_ids are reloaded
|
||||
end
|
||||
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ RSpec.describe NamespaceSetting, feature_category: :groups_and_projects, type: :
|
|||
end
|
||||
|
||||
it { is_expected.to define_enum_for(:jobs_to_be_done).with_values([:basics, :move_repository, :code_storage, :exploring, :ci, :other]).with_suffix }
|
||||
it { is_expected.to define_enum_for(:enabled_git_access_protocol).with_values([:all, :ssh, :http]).with_suffix }
|
||||
it { is_expected.to define_enum_for(:enabled_git_access_protocol).with_suffix }
|
||||
|
||||
describe 'default values' do
|
||||
subject(:setting) { described_class.new }
|
||||
|
|
|
|||
|
|
@ -661,23 +661,7 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
|
|||
end
|
||||
|
||||
context 'traversal scopes' do
|
||||
context 'recursive' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'namespace traversal scopes'
|
||||
end
|
||||
|
||||
context 'linear' do
|
||||
it_behaves_like 'namespace traversal scopes'
|
||||
end
|
||||
|
||||
shared_examples 'makes recursive queries' do
|
||||
specify do
|
||||
expect { subject }.to make_queries_matching(/WITH RECURSIVE/)
|
||||
end
|
||||
end
|
||||
it_behaves_like 'namespace traversal scopes'
|
||||
|
||||
shared_examples 'does not make recursive queries' do
|
||||
specify do
|
||||
|
|
@ -691,14 +675,6 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
|
|||
subject { described_class.where(id: namespace).self_and_descendants.load }
|
||||
|
||||
it_behaves_like 'does not make recursive queries'
|
||||
|
||||
context 'when feature flag :use_traversal_ids is disabled' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'makes recursive queries'
|
||||
end
|
||||
end
|
||||
|
||||
describe '.self_and_descendant_ids' do
|
||||
|
|
@ -707,14 +683,6 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
|
|||
subject { described_class.where(id: namespace).self_and_descendant_ids.load }
|
||||
|
||||
it_behaves_like 'does not make recursive queries'
|
||||
|
||||
context 'when feature flag :use_traversal_ids is disabled' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'makes recursive queries'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1292,30 +1260,6 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
|
|||
it { is_expected.to eq false }
|
||||
end
|
||||
|
||||
describe '#use_traversal_ids?' do
|
||||
let_it_be(:namespace, reload: true) { create(:namespace) }
|
||||
|
||||
subject { namespace.use_traversal_ids? }
|
||||
|
||||
context 'when use_traversal_ids feature flag is true' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: true)
|
||||
end
|
||||
|
||||
it { is_expected.to eq true }
|
||||
|
||||
it_behaves_like 'disabled feature flag when traversal_ids is blank'
|
||||
end
|
||||
|
||||
context 'when use_traversal_ids feature flag is false' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
it { is_expected.to eq false }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#users_with_descendants' do
|
||||
let(:user_a) { create(:user) }
|
||||
let(:user_b) { create(:user) }
|
||||
|
|
@ -1419,28 +1363,14 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
|
|||
end
|
||||
|
||||
describe '#all_projects' do
|
||||
context 'with use_traversal_ids feature flag enabled' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: true)
|
||||
end
|
||||
include_examples '#all_projects'
|
||||
|
||||
include_examples '#all_projects'
|
||||
|
||||
# Using #self_and_descendant instead of #self_and_descendant_ids can produce
|
||||
# very slow queries.
|
||||
it 'calls self_and_descendant_ids' do
|
||||
namespace = create(:group)
|
||||
expect(namespace).to receive(:self_and_descendant_ids)
|
||||
namespace.all_projects
|
||||
end
|
||||
end
|
||||
|
||||
context 'with use_traversal_ids feature flag disabled' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
include_examples '#all_projects'
|
||||
# Using #self_and_descendant instead of #self_and_descendant_ids can produce
|
||||
# very slow queries.
|
||||
it 'calls self_and_descendant_ids' do
|
||||
namespace = create(:group)
|
||||
expect(namespace).to receive(:self_and_descendant_ids)
|
||||
namespace.all_projects
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe PagesDomain do
|
||||
RSpec.describe PagesDomain, feature_category: :pages do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
subject(:pages_domain) { described_class.new }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Preloaders::ProjectRootAncestorPreloader do
|
||||
RSpec.describe Preloaders::ProjectRootAncestorPreloader, feature_category: :system_access do
|
||||
let_it_be(:root_parent1) { create(:group, :private, name: 'root-1', path: 'root-1') }
|
||||
let_it_be(:root_parent2) { create(:group, name: 'root-2', path: 'root-2') }
|
||||
let_it_be(:guest_project) { create(:project, name: 'public guest', path: 'public-guest') }
|
||||
|
|
@ -43,87 +43,47 @@ RSpec.describe Preloaders::ProjectRootAncestorPreloader do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when use_traversal_ids FF is enabled' do
|
||||
context 'when the preloader is used' do
|
||||
context 'when no additional preloads are provided' do
|
||||
before do
|
||||
preload_ancestors(:group)
|
||||
end
|
||||
|
||||
it_behaves_like 'executes N matching DB queries', 0
|
||||
end
|
||||
|
||||
context 'when additional preloads are provided' do
|
||||
let(:additional_preloads) { [:route] }
|
||||
let(:root_query_regex) { /\ASELECT.+FROM "routes" WHERE "routes"."source_id" = \d+/ }
|
||||
|
||||
before do
|
||||
preload_ancestors
|
||||
end
|
||||
|
||||
it_behaves_like 'executes N matching DB queries', 0, :full_path
|
||||
end
|
||||
|
||||
context 'when projects are an array and not an ActiveRecord::Relation' do
|
||||
before do
|
||||
described_class.new(projects, :namespace, additional_preloads).execute
|
||||
end
|
||||
|
||||
it_behaves_like 'executes N matching DB queries', 4
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the preloader is not used' do
|
||||
it_behaves_like 'executes N matching DB queries', 4
|
||||
end
|
||||
|
||||
context 'when using a :group sti name and passing projects in a user namespace' do
|
||||
let(:projects) { [private_developer_project] }
|
||||
let(:additional_preloads) { [:ip_restrictions, :saml_provider] }
|
||||
|
||||
it 'does not load a nil value for root_ancestor' do
|
||||
context 'when the preloader is used' do
|
||||
context 'when no additional preloads are provided' do
|
||||
before do
|
||||
preload_ancestors(:group)
|
||||
|
||||
expect(pristine_projects.first.root_ancestor).to eq(private_developer_project.root_ancestor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when use_traversal_ids FF is disabled' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
it_behaves_like 'executes N matching DB queries', 0
|
||||
end
|
||||
|
||||
context 'when the preloader is used' do
|
||||
context 'when additional preloads are provided' do
|
||||
let(:additional_preloads) { [:route] }
|
||||
let(:root_query_regex) { /\ASELECT.+FROM "routes" WHERE "routes"."source_id" = \d+/ }
|
||||
|
||||
before do
|
||||
preload_ancestors
|
||||
end
|
||||
|
||||
context 'when no additional preloads are provided' do
|
||||
it_behaves_like 'executes N matching DB queries', 4
|
||||
end
|
||||
|
||||
context 'when additional preloads are provided' do
|
||||
let(:additional_preloads) { [:route] }
|
||||
let(:root_query_regex) { /\ASELECT.+FROM "routes" WHERE "routes"."source_id" = \d+/ }
|
||||
|
||||
it_behaves_like 'executes N matching DB queries', 4, :full_path
|
||||
end
|
||||
it_behaves_like 'executes N matching DB queries', 0, :full_path
|
||||
end
|
||||
|
||||
context 'when the preloader is not used' do
|
||||
context 'when projects are an array and not an ActiveRecord::Relation' do
|
||||
before do
|
||||
described_class.new(projects, :namespace, additional_preloads).execute
|
||||
end
|
||||
|
||||
it_behaves_like 'executes N matching DB queries', 4
|
||||
end
|
||||
end
|
||||
|
||||
context 'when using a :group sti name and passing projects in a user namespace' do
|
||||
let(:projects) { [private_developer_project] }
|
||||
let(:additional_preloads) { [:ip_restrictions, :saml_provider] }
|
||||
context 'when the preloader is not used' do
|
||||
it_behaves_like 'executes N matching DB queries', 4
|
||||
end
|
||||
|
||||
it 'does not load a nil value for root_ancestor' do
|
||||
preload_ancestors(:group)
|
||||
context 'when using a :group sti name and passing projects in a user namespace' do
|
||||
let(:projects) { [private_developer_project] }
|
||||
let(:additional_preloads) { [:ip_restrictions, :saml_provider] }
|
||||
|
||||
expect(pristine_projects.first.root_ancestor).to eq(private_developer_project.root_ancestor)
|
||||
end
|
||||
it 'does not load a nil value for root_ancestor' do
|
||||
preload_ancestors(:group)
|
||||
|
||||
expect(pristine_projects.first.root_ancestor).to eq(private_developer_project.root_ancestor)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -34,46 +34,31 @@ RSpec.describe Preloaders::UserMaxAccessLevelInGroupsPreloader, feature_category
|
|||
|
||||
let(:groups) { [group1, group2, group3, child_maintainer, child_indirect_access] }
|
||||
|
||||
context 'when traversal_ids feature flag is disabled' do
|
||||
it_behaves_like 'executes N max member permission queries to the DB' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
described_class.new(groups, user).execute
|
||||
end
|
||||
|
||||
# One query for group with no access and another one per group where the user is not a direct member
|
||||
let(:expected_query_count) { 2 }
|
||||
it_behaves_like 'executes N max member permission queries to the DB' do
|
||||
before do
|
||||
described_class.new(groups, user).execute
|
||||
end
|
||||
|
||||
let(:expected_query_count) { 0 }
|
||||
end
|
||||
|
||||
context 'when traversal_ids feature flag is enabled' do
|
||||
it_behaves_like 'executes N max member permission queries to the DB' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: true)
|
||||
described_class.new(groups, user).execute
|
||||
end
|
||||
context 'for groups arising from group shares' do
|
||||
let_it_be(:group4) { create(:group, :private) }
|
||||
let_it_be(:group4_subgroup) { create(:group, :private, parent: group4) }
|
||||
|
||||
let(:expected_query_count) { 0 }
|
||||
let(:groups) { [group4, group4_subgroup] }
|
||||
|
||||
before do
|
||||
create(:group_group_link, :guest, shared_with_group: group1, shared_group: group4)
|
||||
end
|
||||
|
||||
context 'for groups arising from group shares' do
|
||||
let_it_be(:group4) { create(:group, :private) }
|
||||
let_it_be(:group4_subgroup) { create(:group, :private, parent: group4) }
|
||||
it 'sets the right access level in cache for groups arising from group shares' do
|
||||
described_class.new(groups, user).execute
|
||||
|
||||
let(:groups) { [group4, group4_subgroup] }
|
||||
groups.each do |group|
|
||||
cached_access_level = group.max_member_access_for_user(user)
|
||||
|
||||
before do
|
||||
create(:group_group_link, :guest, shared_with_group: group1, shared_group: group4)
|
||||
end
|
||||
|
||||
it 'sets the right access level in cache for groups arising from group shares' do
|
||||
described_class.new(groups, user).execute
|
||||
|
||||
groups.each do |group|
|
||||
cached_access_level = group.max_member_access_for_user(user)
|
||||
|
||||
expect(cached_access_level).to eq(Gitlab::Access::GUEST)
|
||||
end
|
||||
expect(cached_access_level).to eq(Gitlab::Access::GUEST)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5073,14 +5073,6 @@ RSpec.describe User, feature_category: :user_profile do
|
|||
|
||||
describe '#ci_owned_runners' do
|
||||
it_behaves_like '#ci_owned_runners'
|
||||
|
||||
context 'when FF use_traversal_ids is disabled fallbacks to inefficient implementation' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
it_behaves_like '#ci_owned_runners'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#projects_with_reporter_access_limited_to' do
|
||||
|
|
|
|||
|
|
@ -145,14 +145,6 @@ RSpec.describe Ci::ProcessSyncEventsService, feature_category: :continuous_integ
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the use_traversal_ids FF is disabled' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'event consuming'
|
||||
end
|
||||
|
||||
it_behaves_like 'event consuming'
|
||||
|
||||
it 'enqueues Namespaces::ProcessSyncEventsWorker if any left' do
|
||||
|
|
|
|||
|
|
@ -14,9 +14,21 @@ RSpec.shared_context 'exposing regular notes on a noteable in GraphQL' do
|
|||
let(:user) { note.author }
|
||||
|
||||
context 'for regular notes' do
|
||||
let!(:system_note) do
|
||||
create(
|
||||
:note,
|
||||
system: true,
|
||||
noteable: noteable,
|
||||
project: (noteable.project if noteable.respond_to?(:project))
|
||||
)
|
||||
end
|
||||
|
||||
let(:filters) { "" }
|
||||
|
||||
let(:query) do
|
||||
note_fields = <<~NOTES
|
||||
notes {
|
||||
notes #{filters} {
|
||||
count
|
||||
edges {
|
||||
node {
|
||||
#{all_graphql_fields_for('Note', max_depth: 1)}
|
||||
|
|
@ -42,11 +54,12 @@ RSpec.shared_context 'exposing regular notes on a noteable in GraphQL' do
|
|||
end
|
||||
end
|
||||
|
||||
it 'includes the note' do
|
||||
it 'includes all notes' do
|
||||
post_graphql(query, current_user: user)
|
||||
|
||||
expect(noteable_data['notes']['edges'].first['node']['body'])
|
||||
.to eq(note.note)
|
||||
expect(noteable_data['notes']['count']).to eq(2)
|
||||
expect(noteable_data['notes']['edges'][0]['node']['body']).to eq(system_note.note)
|
||||
expect(noteable_data['notes']['edges'][1]['node']['body']).to eq(note.note)
|
||||
end
|
||||
|
||||
it 'avoids N+1 queries' do
|
||||
|
|
@ -69,6 +82,42 @@ RSpec.shared_context 'exposing regular notes on a noteable in GraphQL' do
|
|||
expect { post_graphql(query, current_user: user) }.not_to exceed_query_limit(control)
|
||||
expect_graphql_errors_to_be_empty
|
||||
end
|
||||
|
||||
context 'when filter is provided' do
|
||||
context 'when filter is set to ALL_NOTES' do
|
||||
let(:filters) { "(filter: ALL_NOTES)" }
|
||||
|
||||
it 'returns all the notes' do
|
||||
post_graphql(query, current_user: user)
|
||||
|
||||
expect(noteable_data['notes']['count']).to eq(2)
|
||||
expect(noteable_data['notes']['edges'][0]['node']['body']).to eq(system_note.note)
|
||||
expect(noteable_data['notes']['edges'][1]['node']['body']).to eq(note.note)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when filter is set to ONLY_COMMENTS' do
|
||||
let(:filters) { "(filter: ONLY_COMMENTS)" }
|
||||
|
||||
it 'returns only the comments' do
|
||||
post_graphql(query, current_user: user)
|
||||
|
||||
expect(noteable_data['notes']['count']).to eq(1)
|
||||
expect(noteable_data['notes']['edges'][0]['node']['body']).to eq(note.note)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when filter is set to ONLY_ACTIVITY' do
|
||||
let(:filters) { "(filter: ONLY_ACTIVITY)" }
|
||||
|
||||
it 'returns only the activity notes' do
|
||||
post_graphql(query, current_user: user)
|
||||
|
||||
expect(noteable_data['notes']['count']).to eq(1)
|
||||
expect(noteable_data['notes']['edges'][0]['node']['body']).to eq(system_note.note)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "for discussions" do
|
||||
|
|
|
|||
|
|
@ -240,14 +240,6 @@ RSpec.shared_examples 'namespace traversal' do
|
|||
|
||||
describe '#ancestors_upto' do
|
||||
include_examples '#ancestors_upto'
|
||||
|
||||
context 'with use_traversal_ids disabled' do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
include_examples '#ancestors_upto'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#descendants' do
|
||||
|
|
|
|||
|
|
@ -70,28 +70,10 @@ RSpec.shared_examples 'namespace traversal scopes' do
|
|||
end
|
||||
|
||||
describe '.roots' do
|
||||
context "use_traversal_ids feature flag is true" do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: true)
|
||||
end
|
||||
it_behaves_like '.roots'
|
||||
|
||||
it_behaves_like '.roots'
|
||||
|
||||
it 'not make recursive queries' do
|
||||
expect { described_class.where(id: [nested_group_1]).roots.load }.not_to make_queries_matching(/WITH RECURSIVE/)
|
||||
end
|
||||
end
|
||||
|
||||
context "use_traversal_ids feature flag is false" do
|
||||
before do
|
||||
stub_feature_flags(use_traversal_ids: false)
|
||||
end
|
||||
|
||||
it_behaves_like '.roots'
|
||||
|
||||
it 'makes recursive queries' do
|
||||
expect { described_class.where(id: [nested_group_1]).roots.load }.to make_queries_matching(/WITH RECURSIVE/)
|
||||
end
|
||||
it 'not make recursive queries' do
|
||||
expect { described_class.where(id: [nested_group_1]).roots.load }.not_to make_queries_matching(/WITH RECURSIVE/)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue