diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-14 15:09:37 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-14 15:09:37 +0300 |
commit | b7f103736153a739f0da400eba20a155e0db2797 (patch) | |
tree | ad802e7e9b38bb66decea4639a60fea0982eacc1 | |
parent | bbacb6748ab541728ac22ee71eb1ffd3884d2a10 (diff) |
Add latest changes from gitlab-org/gitlab@master
67 files changed, 647 insertions, 100 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index ec8377b4ed5..d417dbd188d 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -bb342a5916dd5ecffb8b281de8290066176c2662 +329777f9ba8415599decdced7e9ee54efe7c0b44 diff --git a/app/assets/javascripts/tracking/constants.js b/app/assets/javascripts/tracking/constants.js index d0447fa167c..114587bb363 100644 --- a/app/assets/javascripts/tracking/constants.js +++ b/app/assets/javascripts/tracking/constants.js @@ -20,6 +20,7 @@ export const DEFAULT_SNOWPLOW_OPTIONS = { export const ACTION_ATTR_SELECTOR = '[data-track-action]'; export const LOAD_ACTION_ATTR_SELECTOR = '[data-track-action="render"]'; export const INTERNAL_EVENTS_SELECTOR = '[data-event-tracking]'; +export const LOAD_INTERNAL_EVENTS_SELECTOR = '[data-event-tracking-load="true"]'; export const URLS_CACHE_STORAGE_KEY = 'gl-snowplow-pseudonymized-urls'; diff --git a/app/assets/javascripts/tracking/index.js b/app/assets/javascripts/tracking/index.js index 7c2cd6fde27..ffbd932c02b 100644 --- a/app/assets/javascripts/tracking/index.js +++ b/app/assets/javascripts/tracking/index.js @@ -71,4 +71,5 @@ export function initDefaultTrackers() { Tracking.trackLoadEvents(); InternalEvents.bindInternalEventDocument(); + InternalEvents.trackInternalLoadEvents(); } diff --git a/app/assets/javascripts/tracking/internal_events.js b/app/assets/javascripts/tracking/internal_events.js index 4d9c7761347..a5fbb55ff63 100644 --- a/app/assets/javascripts/tracking/internal_events.js +++ b/app/assets/javascripts/tracking/internal_events.js @@ -1,9 +1,13 @@ import API from '~/api'; import Tracking from './tracking'; -import { GITLAB_INTERNAL_EVENT_CATEGORY, SERVICE_PING_SCHEMA } from './constants'; +import { + GITLAB_INTERNAL_EVENT_CATEGORY, + LOAD_INTERNAL_EVENTS_SELECTOR, + SERVICE_PING_SCHEMA, +} from './constants'; import { Tracker } from './tracker'; -import { InternalEventHandler } from './utils'; +import { InternalEventHandler, createInternalEventPayload } from './utils'; const InternalEvents = { /** @@ -53,6 +57,27 @@ const InternalEvents = { parent.addEventListener(handler.name, handler.func); return handler; }, + /** + * Attaches internal event handlers for load events. + * @param {HTMLElement} parent - element containing event targets + * @returns {Array} + */ + trackInternalLoadEvents(parent = document) { + if (!Tracker.enabled()) { + return []; + } + + const loadEvents = parent.querySelectorAll(LOAD_INTERNAL_EVENTS_SELECTOR); + + loadEvents.forEach((element) => { + const action = createInternalEventPayload(element); + if (action) { + this.track_event(action); + } + }); + + return loadEvents; + }, }; export default InternalEvents; diff --git a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_edit_form.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_edit_form.vue index 387fc5e0d1c..7c3dd5c3623 100644 --- a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_edit_form.vue +++ b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_edit_form.vue @@ -130,7 +130,6 @@ export default { :label="__('Description')" :label-sr-only="!showFieldTitle" label-for="issuable-description" - label-class="gl-pb-0!" class="col-12 gl-px-0 common-note-form" > <markdown-field diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb index b4b2bddcaec..f50cdd2b1de 100644 --- a/app/controllers/groups/settings/ci_cd_controller.rb +++ b/app/controllers/groups/settings/ci_cd_controller.rb @@ -49,7 +49,6 @@ module Groups def define_variables define_ci_variables - define_view_variables end def define_ci_variables @@ -59,10 +58,6 @@ module Groups .map { |variable| variable.present(current_user: current_user) } end - def define_view_variables - @content_class = 'limit-container-width' unless fluid_layout - end - def authorize_admin_group! return render_404 unless can?(current_user, :admin_group, group) end diff --git a/app/finders/work_items/namespace_work_items_finder.rb b/app/finders/work_items/namespace_work_items_finder.rb index 9a59cf836b5..aad99d710b6 100644 --- a/app/finders/work_items/namespace_work_items_finder.rb +++ b/app/finders/work_items/namespace_work_items_finder.rb @@ -2,19 +2,25 @@ module WorkItems class NamespaceWorkItemsFinder < WorkItemsFinder + def initialize(...) + super + + self.parent_param = namespace + end + def execute items = init_collection + items = by_namespace(items) sort(items) end override :with_confidentiality_access_check def with_confidentiality_access_check - return klass.none unless parent && current_user&.can?("read_#{parent.to_ability_name}".to_sym, parent) return model_class.all if params.user_can_see_all_issuables? # Only admins can see hidden issues, so for non-admins, we filter out any hidden issues - issues = model_class.without_hidden.in_namespaces(parent) + issues = model_class.without_hidden return issues.all if params.user_can_see_all_confidential_issues? @@ -22,5 +28,22 @@ module WorkItems issues.with_confidentiality_check(current_user) end + + private + + def by_namespace(items) + if namespace.blank? || !Ability.allowed?(current_user, "read_#{namespace.to_ability_name}".to_sym, namespace) + return klass.none + end + + items.in_namespaces(namespace) + end + + def namespace + return if params[:namespace_id].blank? + + params[:namespace_id].is_a?(Namespace) ? params[:namespace_id] : Namespace.find_by_id(params[:namespace_id]) + end + strong_memoize_attr :namespace end end diff --git a/app/graphql/resolvers/namespaces/work_items_resolver.rb b/app/graphql/resolvers/namespaces/work_items_resolver.rb index c4a2d3886e6..40f4c637a07 100644 --- a/app/graphql/resolvers/namespaces/work_items_resolver.rb +++ b/app/graphql/resolvers/namespaces/work_items_resolver.rb @@ -11,7 +11,9 @@ module Resolvers return unless Feature.enabled?(:namespace_level_work_items) return WorkItem.none if resource_parent.nil? - finder = ::WorkItems::NamespaceWorkItemsFinder.new(current_user, args) + finder = ::WorkItems::NamespaceWorkItemsFinder.new(current_user, args.merge( + namespace_id: resource_parent + )) Gitlab::Graphql::Loaders::IssuableLoader.new(resource_parent, finder).batching_find_all do |q| apply_lookahead(q) diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb index 4026d6261c9..645a08bfcc0 100644 --- a/app/helpers/integrations_helper.rb +++ b/app/helpers/integrations_helper.rb @@ -179,7 +179,8 @@ module IntegrationsHelper 'incident' => _('Incident'), 'test_case' => _('Test case'), 'requirement' => _('Requirement'), - 'task' => _('Task') + 'task' => _('Task'), + 'ticket' => _('Service Desk Ticket') } issue_type_i18n_map[issue_type] || issue_type diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb index 3f9b1986b70..3f9d8f07b06 100644 --- a/app/models/ci/job_artifact.rb +++ b/app/models/ci/job_artifact.rb @@ -344,10 +344,16 @@ module Ci end def to_deleted_object_attrs(pick_up_at = nil) + final_path_store_dir, final_path_filename = nil + if file_final_path.present? + final_path_store_dir = File.dirname(file_final_path) + final_path_filename = File.basename(file_final_path) + end + { file_store: file_store, - store_dir: file.store_dir.to_s, - file: file_identifier, + store_dir: final_path_store_dir || file.store_dir.to_s, + file: final_path_filename || file_identifier, pick_up_at: pick_up_at || expire_at || Time.current } end diff --git a/app/models/work_items/type.rb b/app/models/work_items/type.rb index 88ab3d6bab0..369ffc660aa 100644 --- a/app/models/work_items/type.rb +++ b/app/models/work_items/type.rb @@ -20,7 +20,8 @@ module WorkItems task: 'Task', objective: 'Objective', key_result: 'Key Result', - epic: 'Epic' + epic: 'Epic', + ticket: 'Ticket' }.freeze # Base types need to exist on the DB on app startup @@ -34,7 +35,8 @@ module WorkItems task: { name: TYPE_NAMES[:task], icon_name: 'issue-type-task', enum_value: 4 }, objective: { name: TYPE_NAMES[:objective], icon_name: 'issue-type-objective', enum_value: 5 }, ## EE-only key_result: { name: TYPE_NAMES[:key_result], icon_name: 'issue-type-keyresult', enum_value: 6 }, ## EE-only - epic: { name: TYPE_NAMES[:epic], icon_name: 'issue-type-epic', enum_value: 7 } ## EE-only + epic: { name: TYPE_NAMES[:epic], icon_name: 'issue-type-epic', enum_value: 7 }, ## EE-only + ticket: { name: TYPE_NAMES[:ticket], icon_name: 'issue-type-issue', enum_value: 8 } }.freeze # A list of types user can change between - both original and new @@ -42,7 +44,7 @@ module WorkItems # where it's possible to switch between issue and incident. CHANGEABLE_BASE_TYPES = %w[issue incident test_case].freeze - WI_TYPES_WITH_CREATED_HEADER = %w[issue incident].freeze + WI_TYPES_WITH_CREATED_HEADER = %w[issue incident ticket].freeze cache_markdown_field :description, pipeline: :single_line @@ -81,7 +83,7 @@ module WorkItems end def self.allowed_types_for_issues - base_types.keys.excluding('task', 'objective', 'key_result', 'epic') + base_types.keys.excluding('task', 'objective', 'key_result', 'epic', 'ticket') end def default? diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index dedff502a87..13aedd6e4e0 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -38,7 +38,7 @@ = s_('GroupSettings|Badges') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do = expanded ? _('Collapse') : _('Expand') - %p + %p.gl-text-secondary.gl-mb-0 = s_('GroupSettings|Customize this group\'s badges.') = link_to s_('GroupSettings|What are badges?'), help_page_path('user/project/badges') .settings-content diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index b9149bbd7b3..78878141b80 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -46,7 +46,7 @@ = s_('ProjectSettings|Badges') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do = expanded ? _('Collapse') : _('Expand') - %p + %p.gl-text-secondary.gl-mb-0 = s_('ProjectSettings|Customize this project\'s badges.') = link_to s_('ProjectSettings|What are badges?'), help_page_path('user/project/badges') .settings-content diff --git a/config/feature_flags/development/ci_needs_parallel_matrix.yml b/config/feature_flags/development/ci_needs_parallel_matrix.yml deleted file mode 100644 index 73be4f2e82d..00000000000 --- a/config/feature_flags/development/ci_needs_parallel_matrix.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: ci_needs_parallel_matrix -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118839 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/416479 -milestone: '16.3' -type: development -group: group::pipeline authoring -default_enabled: false diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index 2b47455f17f..03bdc6cf47a 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -29,7 +29,10 @@ end # Custom Queues configuration queues_config_hash = Gitlab::Redis::Queues.params -queues_config_hash[:namespace] = Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE + +unless Gitlab::Utils.to_boolean(ENV['SIDEKIQ_ENQUEUE_NON_NAMESPACED']) + queues_config_hash[:namespace] = Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE +end enable_json_logs = Gitlab.config.sidekiq.log_format == 'json' @@ -86,6 +89,12 @@ Sidekiq.configure_server do |config| end if enable_reliable_fetch? + if Gitlab::Utils.to_boolean(ENV['SIDEKIQ_POLL_NON_NAMESPACED']) + # set non-namespaced store for fetcher to poll both namespaced and non-namespaced queues + config[:alternative_store] = ::Gitlab::Redis::Queues + config[:namespace] = Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE + end + config[:semi_reliable_fetch] = enable_semi_reliable_fetch_mode? Sidekiq::ReliableFetch.setup_reliable_fetch!(config) end diff --git a/data/deprecations/ 16_3_runner-terminationgracepriodseconds.yml b/data/deprecations/ 16_3_runner-terminationgracepriodseconds.yml new file mode 100644 index 00000000000..032032b2196 --- /dev/null +++ b/data/deprecations/ 16_3_runner-terminationgracepriodseconds.yml @@ -0,0 +1,22 @@ +- title: "Deprecate `terminationGracePeriodSeconds` in the GitLab Runner Kubernetes executor" # (required) Clearly explain the change, or planned change. For example, "The `confidential` field for a `Note` is deprecated" or "CI/CD job names will be limited to 250 characters." + removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed + announcement_milestone: "16.3" # (required) The milestone when this feature was first announced as deprecated. + breaking_change: false # (required) Change to false if this is not a breaking change. + reporter: deastman # (required) GitLab username of the person reporting the change + stage: stage # (required) String value of the stage that the feature was created in. e.g., Growth + issue_url: "https://gitlab.com/gitlab-org/gitlab-runner/-/issues/28165" # (required) Link to the deprecation issue in GitLab + body: | # (required) Do not modify this line, instead modify the lines below. + The GitLab Runner Kubernetes executor setting, `terminationGracePeriodSeconds`, is deprecated and will be removed in GitLab 17.0. To manage the cleanup and termination of GitLab Runner worker pods on Kubernetes, customers should instead configure `cleanupGracePeriodSeconds` and `podTerminationGracePeriodSeconds`. For information about how to use the `cleanupGracePeriodSeconds` and `podTerminationGracePeriodSeconds, see the [GitLab Runner Executor documentation](https://docs.gitlab.com/runner/executors/kubernetes.html#other-configtoml-settings). + +# +# OPTIONAL END OF SUPPORT FIELDS +# +# If an End of Support period applies, the announcement should be shared with GitLab Support +# in the `#spt_managers` channel in Slack, and mention `@gitlab-com/support` in this MR. +# + end_of_support_milestone: 17.0 # (optional) Use "XX.YY" format. The milestone when support for this feature will end. + # + # OTHER OPTIONAL FIELDS + # + tiers: [Free, Premium, Ultimate] # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate] + documentation_url: "https://docs.gitlab.com/runner/executors/kubernetes.html" # (optional) This is a link to the current documentation page diff --git a/db/migrate/20230809165212_add_path_prefix_and_build_ref_to_pages_deployments.rb b/db/migrate/20230809165212_add_path_prefix_and_build_ref_to_pages_deployments.rb new file mode 100644 index 00000000000..d2fc8bfc9bc --- /dev/null +++ b/db/migrate/20230809165212_add_path_prefix_and_build_ref_to_pages_deployments.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddPathPrefixAndBuildRefToPagesDeployments < Gitlab::Database::Migration[2.1] + enable_lock_retries! + + # rubocop:disable Migration/AddLimitToTextColumns + # limit is added in 20230809165213_add_index_to_path_prefix_and_ref_to_pages_deployments + def change + add_column :pages_deployments, :path_prefix, :text + add_column :pages_deployments, :build_ref, :text + end + # rubocop:enable Migration/AddLimitToTextColumns +end diff --git a/db/migrate/20230809165213_add_index_to_path_prefix_and_build_ref_to_pages_deployments.rb b/db/migrate/20230809165213_add_index_to_path_prefix_and_build_ref_to_pages_deployments.rb new file mode 100644 index 00000000000..bea4346cfab --- /dev/null +++ b/db/migrate/20230809165213_add_index_to_path_prefix_and_build_ref_to_pages_deployments.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class AddIndexToPathPrefixAndBuildRefToPagesDeployments < Gitlab::Database::Migration[2.1] + disable_ddl_transaction! + + TABLE_NAME = :pages_deployments + INDEX_NAME = 'index_pages_deployments_unique_path_prefix_by_project' + + def up + add_text_limit TABLE_NAME, :path_prefix, 128 + add_text_limit TABLE_NAME, :build_ref, 512 + + add_concurrent_index TABLE_NAME, + [:project_id, :path_prefix], + name: INDEX_NAME, + unique: true + end + + def down + remove_text_limit TABLE_NAME, :path_prefix + remove_text_limit TABLE_NAME, :build_ref + + remove_concurrent_index_by_name TABLE_NAME, INDEX_NAME + end +end diff --git a/db/post_migrate/20230804053643_add_ticket_work_item_type.rb b/db/post_migrate/20230804053643_add_ticket_work_item_type.rb new file mode 100644 index 00000000000..4d40622dfb4 --- /dev/null +++ b/db/post_migrate/20230804053643_add_ticket_work_item_type.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +class AddTicketWorkItemType < Gitlab::Database::Migration[2.1] + disable_ddl_transaction! + restrict_gitlab_migration gitlab_schema: :gitlab_main + + ISSUE_ENUM_VALUE = 0 + TICKET_ENUM_VALUE = 8 + TICKET_NAME = 'Ticket' + TICKET_WIDGETS = { + 'Assignees' => 0, + 'Description' => 1, + 'Hierarchy' => 2, + 'Labels' => 3, + 'Milestone' => 4, + 'Notes' => 5, + 'Start and due date' => 6, + 'Health status' => 7, + 'Weight' => 8, + 'Iteration' => 9, + 'Notifications' => 14, + 'Current user todos' => 15, + 'Award emoji' => 16 + }.freeze + + class MigrationWorkItemType < MigrationRecord + self.table_name = 'work_item_types' + end + + class MigrationWidgetDefinition < MigrationRecord + self.table_name = 'work_item_widget_definitions' + end + + class MigrationHierarchyRestriction < MigrationRecord + self.table_name = 'work_item_hierarchy_restrictions' + end + + def up + # New instances will not run this migration and add this type via fixtures + # checking if record exists mostly because migration specs will run all migrations + # and that will conflict with the preloaded base work item types + existing_ticket_work_item_type = MigrationWorkItemType.find_by(base_type: TICKET_ENUM_VALUE, namespace_id: nil) + + return say('Ticket work item type record exists, skipping creation') if existing_ticket_work_item_type + + new_ticket_work_item_type = MigrationWorkItemType.create( + name: TICKET_NAME, + namespace_id: nil, + base_type: TICKET_ENUM_VALUE, + icon_name: 'issue-type-issue' + ) + + return say('Ticket work item type create record failed, skipping creation') if new_ticket_work_item_type.new_record? + + widgets = TICKET_WIDGETS.map do |widget_name, widget_enum_value| + { + work_item_type_id: new_ticket_work_item_type.id, + name: widget_name, + widget_type: widget_enum_value + } + end + + MigrationWidgetDefinition.upsert_all( + widgets, + unique_by: :index_work_item_widget_definitions_on_default_witype_and_name + ) + + issue_type = MigrationWorkItemType.find_by(base_type: ISSUE_ENUM_VALUE, namespace_id: nil) + return say('Issue work item type not found, skipping hierarchy restrictions creation') unless issue_type + + restrictions = [ + { parent_type_id: new_ticket_work_item_type.id, child_type_id: new_ticket_work_item_type.id, maximum_depth: 1 }, + { parent_type_id: new_ticket_work_item_type.id, child_type_id: issue_type.id, maximum_depth: 1 } + ] + + MigrationHierarchyRestriction.upsert_all( + restrictions, + unique_by: :index_work_item_hierarchy_restrictions_on_parent_and_child + ) + end + + def down + # There's the remote possibility that issues could already be + # using this issue type, with a tight foreign constraint. + # Therefore we will not attempt to remove any data. + end +end diff --git a/db/schema_migrations/20230804053643 b/db/schema_migrations/20230804053643 new file mode 100644 index 00000000000..73d57848407 --- /dev/null +++ b/db/schema_migrations/20230804053643 @@ -0,0 +1 @@ +b43f49777ced6b731662cf87af0c0ba31abc4bf21eab7592ba6d8bc9cd4d2f9b
\ No newline at end of file diff --git a/db/schema_migrations/20230809165212 b/db/schema_migrations/20230809165212 new file mode 100644 index 00000000000..72d1751c42e --- /dev/null +++ b/db/schema_migrations/20230809165212 @@ -0,0 +1 @@ +4137f5af1cb4a00144afecac7ad99e926be4f5a8fa501faaab00f4f017c90cf6
\ No newline at end of file diff --git a/db/schema_migrations/20230809165213 b/db/schema_migrations/20230809165213 new file mode 100644 index 00000000000..c0bcff0566e --- /dev/null +++ b/db/schema_migrations/20230809165213 @@ -0,0 +1 @@ +cdab5ff65d93b1883bd75c60efa21ce03031b2678f4535ae2a50a6ca4377c32d
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 17733e361b7..c5c048deb30 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -20295,8 +20295,12 @@ CREATE TABLE pages_deployments ( file_sha256 bytea NOT NULL, size bigint, root_directory text DEFAULT 'public'::text, + path_prefix text, + build_ref text, + CONSTRAINT check_4d04b8dc9a CHECK ((char_length(path_prefix) <= 128)), CONSTRAINT check_5f9132a958 CHECK ((size IS NOT NULL)), CONSTRAINT check_7e938c810a CHECK ((char_length(root_directory) <= 255)), + CONSTRAINT check_b44e900e5c CHECK ((char_length(build_ref) <= 512)), CONSTRAINT check_f0fe8032dd CHECK ((char_length(file) <= 255)) ); @@ -32752,6 +32756,8 @@ CREATE INDEX index_pages_deployments_on_file_store_and_id ON pages_deployments U CREATE INDEX index_pages_deployments_on_project_id ON pages_deployments USING btree (project_id); +CREATE UNIQUE INDEX index_pages_deployments_unique_path_prefix_by_project ON pages_deployments USING btree (project_id, path_prefix); + CREATE INDEX index_pages_domain_acme_orders_on_challenge_token ON pages_domain_acme_orders USING btree (challenge_token); CREATE INDEX index_pages_domain_acme_orders_on_pages_domain_id ON pages_domain_acme_orders USING btree (pages_domain_id); diff --git a/doc/administration/geo/setup/two_single_node_sites.md b/doc/administration/geo/setup/two_single_node_sites.md index bd3da3a46a6..6a5106f4417 100644 --- a/doc/administration/geo/setup/two_single_node_sites.md +++ b/doc/administration/geo/setup/two_single_node_sites.md @@ -7,7 +7,7 @@ type: howto # Set up Geo for two single-node sites **(PREMIUM SELF)** -The following guide provides concise instructions on how to deploy GitLab Geo for a two single-node site installation using two Linux package instances. +The following guide provides concise instructions on how to deploy GitLab Geo for a two single-node site installation using two Linux package instances. Prerequisites: @@ -166,7 +166,7 @@ Prerequisites: This command uses the `external_url` defined in `/etc/gitlab/gitlab.rb`. 1. Create a password for the `gitlab` database user. - + 1. Generate a MD5 hash of the desired password: ```shell @@ -504,7 +504,7 @@ secondary site is a read-only copy. GitLab stores a number of secret values in `/etc/gitlab/gitlab-secrets.json`. This JSON file must be the same across each of the site nodes. You must manually replicate the secret file across all of your secondary sites, although -[issue 3789](https://gitlab.com/gitlab-org/gitlab/-/issues/3789) proposes to change this behavior. +[issue 3789](https://gitlab.com/gitlab-org/gitlab/-/issues/3789) proposes to change this behavior. 1. SSH into a Rails node on your primary site, and execute the command below: @@ -566,7 +566,7 @@ You must manually replicate the secret file across all of your secondary sites, 1. Copy OpenSSH host keys from the primary site. - - If you can access as root one of the primary site nodes serving SSH traffic (usually, the main GitLab Rails application nodes): + - If you can access as root one of the primary site nodes serving SSH traffic (usually, the main GitLab Rails application nodes): ```shell # Run this from the secondary site, change `<primary_site_fqdn>` for the IP or FQDN of the server diff --git a/doc/administration/pages/troubleshooting.md b/doc/administration/pages/troubleshooting.md index 3edbe47e076..a103c793763 100644 --- a/doc/administration/pages/troubleshooting.md +++ b/doc/administration/pages/troubleshooting.md @@ -217,7 +217,7 @@ You may see this error if `pages_external_url` was updated at some point of time 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). 1. Select **Admin Area**. 1. Select **Applications** and then **Add new application**. - 1. Ensure the **Callback URL/Redirect URI** is using the protocol (HTTP or HTTPS) that + 1. Ensure the **Callback URL/Redirect URI** is using the protocol (HTTP or HTTPS) that `pages_external_url` is configured to use. 1. The domain and path components of `Redirect URI` are valid: they should look like `projects.<pages_external_url>/auth`. diff --git a/doc/administration/settings/protected_paths.md b/doc/administration/settings/protected_paths.md index c914b61f0cf..5deba7dca11 100644 --- a/doc/administration/settings/protected_paths.md +++ b/doc/administration/settings/protected_paths.md @@ -11,7 +11,7 @@ Rate limiting is a technique that improves the security and durability of a web application. For more details, see [Rate limits](../../security/rate_limits.md). You can rate limit (protect) specified paths. For these paths, GitLab responds with HTTP status -code `429` to POST requests at protected paths that exceed 10 requests per minute per IP address. +code `429` to POST requests that exceed 10 requests per minute per IP address and GET requests that exceed 10 requests per minute per IP address at protected paths. For example, the following are limited to a maximum 10 requests per minute: diff --git a/doc/administration/settings/rate_limit_on_issues_creation.md b/doc/administration/settings/rate_limit_on_issues_creation.md index f7e7d05a0b5..20f3febbf28 100644 --- a/doc/administration/settings/rate_limit_on_issues_creation.md +++ b/doc/administration/settings/rate_limit_on_issues_creation.md @@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28129) in GitLab 12.10. -Rate limits control the pace at which new epics and issues can be created. +Rate limits control the pace at which new epics and issues can be created. For example, if you set the limit to `300`, the [Projects::IssuesController#create](https://gitlab.com/gitlab-org/gitlab/blob/master/app/controllers/projects/issues_controller.rb) action blocks requests that exceed a rate of 300 per minute. Access to the endpoint is available after one minute. diff --git a/doc/ci/jobs/job_control.md b/doc/ci/jobs/job_control.md index 89719b0a343..585ae7a8f2c 100644 --- a/doc/ci/jobs/job_control.md +++ b/doc/ci/jobs/job_control.md @@ -834,7 +834,7 @@ Quotes around the `dependencies` entry are required. ## Specify a parallelized job using needs with multiple parallelized jobs -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254821) in GitLab 16.3 [with a flag](../../administration/feature_flags.md) named `ci_needs_parallel_matrix`. Disabled by default. +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254821) in GitLab 16.3. You can use variables defined in [`needs:parallel:matrix`](../yaml/index.md#needsparallelmatrix) with multiple parallelized jobs. diff --git a/doc/ci/runners/saas/macos_saas_runner.md b/doc/ci/runners/saas/macos_saas_runner.md index 8550aeb6477..380a8896aba 100644 --- a/doc/ci/runners/saas/macos_saas_runner.md +++ b/doc/ci/runners/saas/macos_saas_runner.md @@ -138,12 +138,12 @@ All GitLab SaaS runners include CDN support in Cocoapods. ### Use GitLab caching Use caching in Cocoapods packages in GitLab to only run `pod install` -when pods change, which can improve build performance. +when pods change, which can improve build performance. To [configure caching](../../../ci/caching/index.md) for your project: 1. Add the `cache` configuration to your `.gitlab-ci.yml` file: - + ```yaml cache: key: @@ -153,7 +153,7 @@ To [configure caching](../../../ci/caching/index.md) for your project: - Pods ``` -1. Add the [`cocoapods-check`](https://guides.cocoapods.org/plugins/optimising-ci-times.html) plugin to your project. +1. Add the [`cocoapods-check`](https://guides.cocoapods.org/plugins/optimising-ci-times.html) plugin to your project. 1. Update the job script to check for installed dependencies before it calls `pod install`: ```shell diff --git a/doc/ci/testing/test_coverage_visualization.md b/doc/ci/testing/test_coverage_visualization.md index dc59e25fa80..aef8b0c7631 100644 --- a/doc/ci/testing/test_coverage_visualization.md +++ b/doc/ci/testing/test_coverage_visualization.md @@ -41,7 +41,7 @@ Other coverage analysis frameworks support the format out of the box, for exampl - [Coverage.py](https://coverage.readthedocs.io/en/coverage-5.0.4/cmd.html#xml-reporting) (Python) - [PHPUnit](https://github.com/sebastianbergmann/phpunit-documentation-english/blob/master/src/textui.rst#command-line-options) (PHP) -After configuration, if your merge request triggers a pipeline that collects coverage reports, the coverage information is displayed in the diff view. This includes reports +After configuration, if your merge request triggers a pipeline that collects coverage reports, the coverage information is displayed in the diff view. This includes reports from any job in any stage in the pipeline. The coverage displays for each line: - `covered` (green): lines which have been checked at least once by tests diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md index 94ec290b2db..654ebffe8e6 100644 --- a/doc/ci/yaml/index.md +++ b/doc/ci/yaml/index.md @@ -2683,7 +2683,7 @@ upstream_status: #### `needs:parallel:matrix` -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254821) in GitLab 16.3 [with a flag](../../administration/feature_flags.md) named `ci_needs_parallel_matrix`. Disabled by default. +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254821) in GitLab 16.3. Jobs can use [`parallel:matrix`](#parallelmatrix) to run a job multiple times in parallel in a single pipeline, but with different variable values for each instance of the job. diff --git a/doc/development/ai_architecture.md b/doc/development/ai_architecture.md index 0490613b116..84a2635b13c 100644 --- a/doc/development/ai_architecture.md +++ b/doc/development/ai_architecture.md @@ -25,7 +25,7 @@ There are two primary reasons for this: the best AI models are cloud-based as th ## AI Gateway -The AI Gateway (formerly the [model gateway](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist)) is a standalone-service that will give access to AI features to all users of GitLab, no matter which instance they are using: self-managed, dedicated or GitLab.com. The SaaS-based AI abstraction layer will transition to connecting to this gateway, rather than accessing cloud-based providers directly. +The AI Gateway (formerly the [model gateway](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist)) is a standalone-service that will give access to AI features to all users of GitLab, no matter which instance they are using: self-managed, dedicated or GitLab.com. The SaaS-based AI abstraction layer will transition to connecting to this gateway, rather than accessing cloud-based providers directly. ## Supported technologies @@ -100,6 +100,6 @@ The following table documents functionality that Code Suggestions offers today, Code Suggestions acceptance rates are _highly_ sensitive to latency. While writing code with an AI assistant, a user will pause only for a short duration before continuing on with manually typing out a block of code. As soon as the user has pressed a subsequent keypress, the existing suggestion will be invalidated and a new request will need to be issued to the code suggestions endpoint. In turn, this request will also be highly sensitive to latency. -In a worst case with sufficient latency, the IDE could be issuing a string of requests, each of which is then ignored as the user proceeds without waiting for the response. This adds no value for the user, while still putting load on our services. +In a worst case with sufficient latency, the IDE could be issuing a string of requests, each of which is then ignored as the user proceeds without waiting for the response. This adds no value for the user, while still putting load on our services. See our discussions [here](https://gitlab.com/gitlab-org/gitlab/-/issues/418955) around how we plan to iterate on latency for this feature. diff --git a/doc/development/gitlab_shell/index.md b/doc/development/gitlab_shell/index.md index 3af9dd04f38..2cdfb68f84d 100644 --- a/doc/development/gitlab_shell/index.md +++ b/doc/development/gitlab_shell/index.md @@ -33,7 +33,7 @@ and support: There are two version files relevent to GitLab Shell: - [Stable version](https://gitlab.com/gitlab-org/gitlab-shell/-/blob/main/VERSION) -- [Version deployed in GitLab SaaS](https://gitlab.com/gitlab-org/gitlab/-/blob/master/GITLAB_SHELL_VERSION) +- [Version deployed in GitLab SaaS](https://gitlab.com/gitlab-org/gitlab/-/blob/master/GITLAB_SHELL_VERSION) GitLab team members can also monitor the `#announcements` internal Slack channel. diff --git a/doc/development/internal_analytics/internal_event_tracking/quick_start.md b/doc/development/internal_analytics/internal_event_tracking/quick_start.md index a95ee16644e..84926657a3b 100644 --- a/doc/development/internal_analytics/internal_event_tracking/quick_start.md +++ b/doc/development/internal_analytics/internal_event_tracking/quick_start.md @@ -96,3 +96,18 @@ This attribute ensures that if we want to track GitLab internal events for a but Click Me </gl-button> ``` + +For Haml + +```haml += render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle', data: { event_tracking: 'action' }}) do +``` + +#### Internal events on render + +Sometimes we want to send internal events when the component is rendered or loaded. In these cases, we can add the `data-event-tracking-load="true"` attribute: + +```haml += render Pajamas::ButtonComponent.new(button_options: { data: { event_tracking_load: 'true', event_tracking: 'i_devops' } }) do + = _("New project") +``` diff --git a/doc/subscriptions/customers_portal.md b/doc/subscriptions/customers_portal.md index 34069545853..45a4324f45d 100644 --- a/doc/subscriptions/customers_portal.md +++ b/doc/subscriptions/customers_portal.md @@ -29,7 +29,7 @@ To sign in to Customers Portal with your email and to receive a one-time sign-in 1. Navigate to [Customers Portal](https://customers.gitlab.com/customers/sign_in). 1. Select **Sign in with your email**. -1. Provide the **Email** for your Customers Portal account. You will receive +1. Provide the **Email** for your Customers Portal account. You will receive an email with a one-time, sign-in link for your Customers Portal account. 1. In the email you received, select **Sign in**. diff --git a/doc/tutorials/website_project_with_analytics/index.md b/doc/tutorials/website_project_with_analytics/index.md index 3ae33fa4f41..d8a079d545f 100644 --- a/doc/tutorials/website_project_with_analytics/index.md +++ b/doc/tutorials/website_project_with_analytics/index.md @@ -82,7 +82,7 @@ To create a project label, in the `My website` project: 1. Select **Manage > Labels**. 1. Select **New label**. -1. In the **Title** field, enter `feature request`. +1. In the **Title** field, enter `feature request`. 1. Optional. In the **Description** field, enter additional information about how and when to use this label. 1. Optional. Select a color by selecting from the available colors, or enter a hex color value for a specific color in the **Background color** field. 1. Select **Create label**. diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md index 8213ee8c0e7..08a5a3a7549 100644 --- a/doc/update/deprecations.md +++ b/doc/update/deprecations.md @@ -172,6 +172,21 @@ The message field was removed from security reports schema in GitLab 16.0 and is </div> +<div class="deprecation " data-milestone="17.0"> + +### Deprecate `terminationGracePeriodSeconds` in the GitLab Runner Kubernetes executor + +<div class="deprecation-notes"> +- Announced in GitLab <span class="milestone">16.3</span> +- End of Support in GitLab <span class="milestone">17.0</span> +- Removal in GitLab <span class="milestone">17.0</span> +- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/28165). +</div> + +The GitLab Runner Kubernetes executor setting, `terminationGracePeriodSeconds`, is deprecated and will be removed in GitLab 17.0. To manage the cleanup and termination of GitLab Runner worker pods on Kubernetes, customers should instead configure `cleanupGracePeriodSeconds` and `podTerminationGracePeriodSeconds`. For information about how to use the `cleanupGracePeriodSeconds` and `podTerminationGracePeriodSeconds, see the [GitLab Runner Executor documentation](https://docs.gitlab.com/runner/executors/kubernetes.html#other-configtoml-settings). + +</div> + <div class="deprecation breaking-change" data-milestone="17.0"> ### Deprecate field `hasSolutions` from GraphQL VulnerabilityType diff --git a/doc/update/versions/gitlab_16_changes.md b/doc/update/versions/gitlab_16_changes.md index d86a6b1b612..55648c87712 100644 --- a/doc/update/versions/gitlab_16_changes.md +++ b/doc/update/versions/gitlab_16_changes.md @@ -31,7 +31,7 @@ Specific information applies to Linux package installations: drop support for it. For more information, see: - + - [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.8). - [An informal explanation](https://gitlab.com/gitlab-org/gitlab/-/issues/416714#note_1482388504). - `omnibus-gitlab` [merge request 7035](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/7035), which introduces the environment variable. diff --git a/doc/user/analytics/dora_metrics.md b/doc/user/analytics/dora_metrics.md index 61aa0d4001a..120142aacee 100644 --- a/doc/user/analytics/dora_metrics.md +++ b/doc/user/analytics/dora_metrics.md @@ -131,7 +131,7 @@ To improve this metric, you should consider: The DORA metrics are displayed on the following charts: -- [Value Streams Dashboard](value_streams_dashboard.md), which helps you identify trends, patterns, and opportunities for improvement. DORA metrics are displayed in the [metrics comparison panel](value_streams_dashboard.md#devsecops-metrics-comparison-panel) and the [DORA Performers score panel](value_streams_dashboard.md#dora-performers-score-panel). +- [Value Streams Dashboard](value_streams_dashboard.md), which helps you identify trends, patterns, and opportunities for improvement. DORA metrics are displayed in the [metrics comparison panel](value_streams_dashboard.md#devsecops-metrics-comparison-panel) and the [DORA Performers score panel](value_streams_dashboard.md#dora-performers-score-panel). - [CI/CD analytics charts](ci_cd_analytics.md), which show pipeline success rates and duration, and the history of DORA metrics over time. - Insights reports for [groups](../group/insights/index.md) and [projects](value_stream_analytics.md), where you can also use [DORA query parameters](../../user/project/insights/index.md#dora-query-parameters) to create custom charts. diff --git a/doc/user/clusters/agent/gitops/flux_oci_tutorial.md b/doc/user/clusters/agent/gitops/flux_oci_tutorial.md index 2ac997b2028..5b73a1c8b4f 100644 --- a/doc/user/clusters/agent/gitops/flux_oci_tutorial.md +++ b/doc/user/clusters/agent/gitops/flux_oci_tutorial.md @@ -9,7 +9,7 @@ info: A tutorial for deploying an OCI artifact using Flux This tutorial teaches you how to package your Kubernetes manifests into an [OCI](https://opencontainers.org/) artifact and deploy them to your cluster using Flux. You'll set up a sample manifest project, configure it to store manifests as an artifact in the project's Container Registry, and configure Flux to sync the artifact. With this -setup, you can run additional steps in GitLab pipelines before Flux picks up the changes +setup, you can run additional steps in GitLab pipelines before Flux picks up the changes from the OCI image. This tutorial deploys an application from a public project. If you want to add a non-public project, you should create a [project deploy token](../../../project/deploy_tokens/index.md). diff --git a/doc/user/group/manage.md b/doc/user/group/manage.md index 48685325dd0..d97c4c3d503 100644 --- a/doc/user/group/manage.md +++ b/doc/user/group/manage.md @@ -304,7 +304,7 @@ To approve members that are pending because they've exceeded the user cap: The user cap cannot be enabled if a group, subgroup, or project is shared externally. If a group, subgroup, or project is shared externally, it is shared outside of the namespace hierarchy, regardless of its level -in the hierarchy. +in the hierarchy. To ensure that the user cap applies when groups, subgroups, or projects are shared externally, restrict group sharing only within the top-level namespace. This ensure that groups in the same top-leve namespace can be invited, and prevents the addition of new users (seats) when the group is shared. @@ -503,7 +503,7 @@ To disable third-party AI features for a group: 1. Select **Save changes**. When Code Suggestions are enabled and disabled, an -[audit event](../../administration/audit_events.md#view-audit-events) is created. +[audit event](../../administration/audit_events.md#view-audit-events) is created. ## Group activity analytics **(PREMIUM)** diff --git a/doc/user/project/repository/branches/default.md b/doc/user/project/repository/branches/default.md index c9cba2e23b7..329ae16c7ab 100644 --- a/doc/user/project/repository/branches/default.md +++ b/doc/user/project/repository/branches/default.md @@ -115,7 +115,7 @@ at the [instance level](#instance-level-default-branch-protection) and and force push. WARNING: -Unless **Fully protected** is chosen, a malicious developer could attempt to steal your sensitive data. For example, a malicious `.gitlab-ci.yml` file could be committed to a protected branch and later, if a pipeline is run against that branch, result in exfiltration of group CI/CD variables. +Unless **Fully protected** is chosen, a malicious developer could attempt to steal your sensitive data. For example, a malicious `.gitlab-ci.yml` file could be committed to a protected branch and later, if a pipeline is run against that branch, result in exfiltration of group CI/CD variables. ### Instance-level default branch protection **(FREE SELF)** diff --git a/doc/user/project/repository/code_suggestions.md b/doc/user/project/repository/code_suggestions.md index deaa095f530..f3a22fd94bd 100644 --- a/doc/user/project/repository/code_suggestions.md +++ b/doc/user/project/repository/code_suggestions.md @@ -236,10 +236,10 @@ Learn more about Google Vertex AI Codey APIs [Data Governance](https://cloud.goo ### Inference window context -Code Suggestions currently inferences against the currently opened file and has a context window of 2,048 tokens and 8,192 character limits. This limit includes content before and after the cursor, the file name, and the extension type. +Code Suggestions currently inferences against the currently opened file and has a context window of 2,048 tokens and 8,192 character limits. This limit includes content before and after the cursor, the file name, and the extension type. Learn more about Google Vertex AI [code-gecko](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/models). -The maximum number of tokens that is generated in the response is default 64. A token is approximately four characters. 100 tokens correspond to roughly 60-80 words. +The maximum number of tokens that is generated in the response is default 64. A token is approximately four characters. 100 tokens correspond to roughly 60-80 words. Learn more about Google Vertex AI [`code-gecko`](https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/code-completion). ### Self-managed instance data privacy diff --git a/doc/user/project/settings/project_access_tokens.md b/doc/user/project/settings/project_access_tokens.md index 8cbda3df0d2..78620eb2ab3 100644 --- a/doc/user/project/settings/project_access_tokens.md +++ b/doc/user/project/settings/project_access_tokens.md @@ -79,7 +79,7 @@ To revoke a project access token: ## Scopes for a project access token -The scope determines the actions you can perform when you authenticate with a project access token. +The scope determines the actions you can perform when you authenticate with a project access token. NOTE: See the warning in [create a project access token](#create-a-project-access-token) regarding internal projects. diff --git a/lib/gitlab/ci/config/entry/need.rb b/lib/gitlab/ci/config/entry/need.rb index 2013e0842e7..cf727134f32 100644 --- a/lib/gitlab/ci/config/entry/need.rb +++ b/lib/gitlab/ci/config/entry/need.rb @@ -71,7 +71,7 @@ module Gitlab optional: !!optional } - result[:parallel] = parallel_value if Feature.enabled?(:ci_needs_parallel_matrix) && has_parallel? + result[:parallel] = parallel_value if has_parallel? result end diff --git a/lib/gitlab/ci/config/entry/needs.rb b/lib/gitlab/ci/config/entry/needs.rb index 79d5a9be98b..f0bfad80e6f 100644 --- a/lib/gitlab/ci/config/entry/needs.rb +++ b/lib/gitlab/ci/config/entry/needs.rb @@ -22,7 +22,7 @@ module Gitlab errors.add(:config, 'can not be an empty Hash') end - if Feature.enabled?(:ci_needs_parallel_matrix) && number_parallel_build? + if number_parallel_build? errors.add(:config, 'cannot use "parallel: <number>".') end end diff --git a/lib/gitlab/ci/config/normalizer.rb b/lib/gitlab/ci/config/normalizer.rb index dde462865f4..a5b692b26d6 100644 --- a/lib/gitlab/ci/config/normalizer.rb +++ b/lib/gitlab/ci/config/normalizer.rb @@ -44,7 +44,7 @@ module Gitlab job_need_name = job_need[:name].to_sym if all_jobs = parallelized_jobs[job_need_name] - if Feature.enabled?(:ci_needs_parallel_matrix) && job_need.key?(:parallel) + if job_need.key?(:parallel) all_jobs = parallelize_job_config(job_need_name, job_need.delete(:parallel)) end diff --git a/lib/gitlab/database_importers/work_items/base_type_importer.rb b/lib/gitlab/database_importers/work_items/base_type_importer.rb index a0738d5c6f8..990fd53a370 100644 --- a/lib/gitlab/database_importers/work_items/base_type_importer.rb +++ b/lib/gitlab/database_importers/work_items/base_type_importer.rb @@ -126,6 +126,21 @@ module Gitlab :notifications, :award_emoji, :linked_items + ], + ticket: [ + :assignees, + :labels, + :description, + :hierarchy, + :start_and_due_date, + :milestone, + :notes, + :iteration, + :weight, + :health_status, + :notifications, + :current_user_todos, + :award_emoji ] }.freeze diff --git a/lib/gitlab/database_importers/work_items/hierarchy_restrictions_importer.rb b/lib/gitlab/database_importers/work_items/hierarchy_restrictions_importer.rb index a203b5e13d0..4e7a4ec748b 100644 --- a/lib/gitlab/database_importers/work_items/hierarchy_restrictions_importer.rb +++ b/lib/gitlab/database_importers/work_items/hierarchy_restrictions_importer.rb @@ -11,6 +11,7 @@ module Gitlab task = find_or_create_type(::WorkItems::Type::TYPE_NAMES[:task]) incident = find_or_create_type(::WorkItems::Type::TYPE_NAMES[:incident]) epic = find_or_create_type(::WorkItems::Type::TYPE_NAMES[:epic]) + ticket = find_or_create_type(::WorkItems::Type::TYPE_NAMES[:ticket]) restrictions = [ { parent_type_id: objective.id, child_type_id: objective.id, maximum_depth: 9 }, @@ -18,7 +19,8 @@ module Gitlab { parent_type_id: issue.id, child_type_id: task.id, maximum_depth: 1 }, { parent_type_id: incident.id, child_type_id: task.id, maximum_depth: 1 }, { parent_type_id: epic.id, child_type_id: epic.id, maximum_depth: 9 }, - { parent_type_id: epic.id, child_type_id: issue.id, maximum_depth: 1 } + { parent_type_id: epic.id, child_type_id: issue.id, maximum_depth: 1 }, + { parent_type_id: ticket.id, child_type_id: task.id, maximum_depth: 1 } ] ::WorkItems::HierarchyRestriction.upsert_all( diff --git a/lib/sidebars/groups/menus/packages_registries_menu.rb b/lib/sidebars/groups/menus/packages_registries_menu.rb index bd1cca6473a..b2d6aec1a78 100644 --- a/lib/sidebars/groups/menus/packages_registries_menu.rb +++ b/lib/sidebars/groups/menus/packages_registries_menu.rb @@ -50,7 +50,7 @@ module Sidebars ::Sidebars::MenuItem.new( title: _('Container Registry'), link: group_container_registries_path(context.group), - super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::OperationsMenu, + super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::DeployMenu, active_routes: { controller: 'groups/registry/repositories' }, item_id: :container_registry ) diff --git a/lib/sidebars/groups/super_sidebar_menus/deploy_menu.rb b/lib/sidebars/groups/super_sidebar_menus/deploy_menu.rb index fe9cc5280c7..b58ad0ee361 100644 --- a/lib/sidebars/groups/super_sidebar_menus/deploy_menu.rb +++ b/lib/sidebars/groups/super_sidebar_menus/deploy_menu.rb @@ -17,7 +17,8 @@ module Sidebars override :configure_menu_items def configure_menu_items [ - :packages_registry + :packages_registry, + :container_registry ].each { |id| add_item(::Sidebars::NilMenuItem.new(item_id: id)) } end end diff --git a/lib/sidebars/groups/super_sidebar_menus/operations_menu.rb b/lib/sidebars/groups/super_sidebar_menus/operations_menu.rb index e716801486e..8988ffc9283 100644 --- a/lib/sidebars/groups/super_sidebar_menus/operations_menu.rb +++ b/lib/sidebars/groups/super_sidebar_menus/operations_menu.rb @@ -18,7 +18,6 @@ module Sidebars def configure_menu_items [ :dependency_proxy, - :container_registry, :group_kubernetes_clusters ].each { |id| add_item(::Sidebars::NilMenuItem.new(item_id: id)) } end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 0e2abef08d7..42a0a1e4597 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -11997,6 +11997,9 @@ msgstr "" msgid "Compliance framework" msgstr "" +msgid "ComplianceFrameworks|Active compliance frameworks" +msgstr "" + msgid "ComplianceFrameworks|Add framework" msgstr "" @@ -12054,7 +12057,7 @@ msgstr "" msgid "ComplianceFrameworks|Error setting the default compliance frameworks" msgstr "" -msgid "ComplianceFrameworks|Frameworks that have been added will appear here." +msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above." msgstr "" msgid "ComplianceFrameworks|Invalid format" @@ -43318,6 +43321,9 @@ msgstr "" msgid "Service Desk" msgstr "" +msgid "Service Desk Ticket" +msgstr "" + msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email." msgstr "" @@ -52248,6 +52254,9 @@ msgstr "" msgid "Vulnerability|GitLab Security Report" msgstr "" +msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below." +msgstr "" + msgid "Vulnerability|Hide prompt" msgstr "" @@ -52401,6 +52410,9 @@ msgstr "" msgid "Vulnerability|Vulnerable method:" msgstr "" +msgid "Vulnerability|Warning: possible secrets detected" +msgstr "" + msgid "WARNING:" msgstr "" diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb index 974c98379f3..3f17d4d5a97 100644 --- a/spec/factories/issues.rb +++ b/spec/factories/issues.rb @@ -97,6 +97,10 @@ FactoryBot.define do association :work_item_type, :default, :epic end + trait :ticket do + association :work_item_type, :default, :ticket + end + factory :incident do association :work_item_type, :default, :incident diff --git a/spec/factories/work_items.rb b/spec/factories/work_items.rb index 5b1e5205c18..4a2186f2fcf 100644 --- a/spec/factories/work_items.rb +++ b/spec/factories/work_items.rb @@ -62,11 +62,20 @@ FactoryBot.define do association :work_item_type, :default, :epic end + trait :ticket do + association :work_item_type, :default, :ticket + end + before(:create, :build) do |work_item, evaluator| if evaluator.namespace.present? work_item.project = nil work_item.namespace = evaluator.namespace end end + + # Service Desk Ticket + factory :ticket do + association :work_item_type, :default, :ticket + end end end diff --git a/spec/finders/work_items/namespace_work_items_finder_spec.rb b/spec/finders/work_items/namespace_work_items_finder_spec.rb index 0b314a9635d..71fde0546ee 100644 --- a/spec/finders/work_items/namespace_work_items_finder_spec.rb +++ b/spec/finders/work_items/namespace_work_items_finder_spec.rb @@ -42,10 +42,9 @@ RSpec.describe WorkItems::NamespaceWorkItemsFinder, feature_category: :team_plan let(:namespace) { nil } subject do - finder = described_class.new(current_user, finder_params) - finder.parent_param = namespace - - finder.execute + described_class.new(current_user, finder_params.merge( + namespace_id: namespace + )).execute end context 'when no parent is provided' do @@ -92,7 +91,13 @@ RSpec.describe WorkItems::NamespaceWorkItemsFinder, feature_category: :team_plan context 'when user is admin' do let(:current_user) { create(:user, :admin).tap { |u| enable_admin_mode!(u) } } - it { is_expected.to match_array(WorkItem.all.to_a) } + it { is_expected.to contain_exactly(group_work_item, group_confidential_work_item, hidden_work_item) } + end + + context 'with an anonymous user' do + let(:current_user) { nil } + + it { is_expected.to contain_exactly(group_work_item) } end context 'when the user can not see confidential work_items' do diff --git a/spec/frontend/tracking/internal_events_spec.js b/spec/frontend/tracking/internal_events_spec.js index 2ee12300a34..ca244c25b06 100644 --- a/spec/frontend/tracking/internal_events_spec.js +++ b/spec/frontend/tracking/internal_events_spec.js @@ -2,7 +2,11 @@ import API from '~/api'; import { mockTracking } from 'helpers/tracking_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import InternalEvents from '~/tracking/internal_events'; -import { GITLAB_INTERNAL_EVENT_CATEGORY, SERVICE_PING_SCHEMA } from '~/tracking/constants'; +import { + GITLAB_INTERNAL_EVENT_CATEGORY, + SERVICE_PING_SCHEMA, + LOAD_INTERNAL_EVENTS_SELECTOR, +} from '~/tracking/constants'; import * as utils from '~/tracking/utils'; import { Tracker } from '~/tracking/tracker'; @@ -97,4 +101,48 @@ describe('InternalEvents', () => { expect(result).toEqual({ name: 'click', func: expect.any(Function) }); }); }); + + describe('trackInternalLoadEvents', () => { + let querySelectorAllMock; + let mockElements; + const action = 'i_devops_action'; + + beforeEach(() => { + Tracker.enabled.mockReturnValue(true); + querySelectorAllMock = jest.fn(); + document.querySelectorAll = querySelectorAllMock; + }); + + it('should return an empty array if Tracker is not enabled', () => { + Tracker.enabled.mockReturnValue(false); + const result = InternalEvents.trackInternalLoadEvents(); + expect(result).toEqual([]); + }); + + describe('tracking', () => { + let trackEventSpy; + beforeEach(() => { + trackEventSpy = jest.spyOn(InternalEvents, 'track_event'); + }); + + it('should track event if action exists', () => { + mockElements = [{ dataset: { eventTracking: action, eventTrackingLoad: true } }]; + querySelectorAllMock.mockReturnValue(mockElements); + + const result = InternalEvents.trackInternalLoadEvents(); + expect(trackEventSpy).toHaveBeenCalledWith(action); + expect(trackEventSpy).toHaveBeenCalledTimes(1); + expect(querySelectorAllMock).toHaveBeenCalledWith(LOAD_INTERNAL_EVENTS_SELECTOR); + expect(result).toEqual(mockElements); + }); + + it('should not track event if action is not present', () => { + mockElements = [{ dataset: { eventTracking: undefined, eventTrackingLoad: true } }]; + querySelectorAllMock.mockReturnValue(mockElements); + + InternalEvents.trackInternalLoadEvents(); + expect(trackEventSpy).toHaveBeenCalledTimes(0); + }); + }); + }); }); diff --git a/spec/helpers/integrations_helper_spec.rb b/spec/helpers/integrations_helper_spec.rb index 1b654995469..6c5a489e664 100644 --- a/spec/helpers/integrations_helper_spec.rb +++ b/spec/helpers/integrations_helper_spec.rb @@ -271,6 +271,7 @@ RSpec.describe IntegrationsHelper, feature_category: :integrations do "test_case" | _('Test case') "requirement" | _('Requirement') "task" | _('Task') + "ticket" | _('Service Desk Ticket') end with_them do @@ -285,7 +286,7 @@ RSpec.describe IntegrationsHelper, feature_category: :integrations do end it "only consider these enumeration values are valid" do - expected_valid_types = %w[issue incident test_case requirement task objective key_result epic] + expected_valid_types = %w[issue incident test_case requirement task objective key_result epic ticket] expect(WorkItems::Type.base_types.keys).to contain_exactly(*expected_valid_types) end end diff --git a/spec/lib/gitlab/ci/config/normalizer_spec.rb b/spec/lib/gitlab/ci/config/normalizer_spec.rb index 5436a6f83e2..cc549b38dc3 100644 --- a/spec/lib/gitlab/ci/config/normalizer_spec.rb +++ b/spec/lib/gitlab/ci/config/normalizer_spec.rb @@ -128,22 +128,6 @@ RSpec.describe Gitlab::Ci::Config::Normalizer do it 'parallelizes and only keeps needs specified by needs:parallel:matrix' do expect(subject.dig(:other_job, :needs, :job)).to eq(expanded_needs_parallel_job_attributes) end - - context 'when FF `ci_needs_parallel_matrix` is disabled' do - before do - stub_feature_flags(ci_needs_parallel_matrix: false) - end - - let(:expanded_job_attributes) do - expanded_job_names.map do |job_name| - { name: job_name, parallel: needs_parallel_config } - end - end - - it 'keeps all parallelized jobs' do - expect(subject.dig(:other_job, :needs, :job)).to eq(expanded_job_attributes) - end - end end end diff --git a/spec/lib/sidebars/groups/super_sidebar_menus/deploy_menu_spec.rb b/spec/lib/sidebars/groups/super_sidebar_menus/deploy_menu_spec.rb index ec3f911d8dc..edb3f5f610a 100644 --- a/spec/lib/sidebars/groups/super_sidebar_menus/deploy_menu_spec.rb +++ b/spec/lib/sidebars/groups/super_sidebar_menus/deploy_menu_spec.rb @@ -15,7 +15,8 @@ RSpec.describe Sidebars::Groups::SuperSidebarMenus::DeployMenu, feature_category it 'defines list of NilMenuItem placeholders' do expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) expect(items.map(&:item_id)).to eq([ - :packages_registry + :packages_registry, + :container_registry ]) end end diff --git a/spec/lib/sidebars/groups/super_sidebar_menus/operations_menu_spec.rb b/spec/lib/sidebars/groups/super_sidebar_menus/operations_menu_spec.rb index df37d5f1b0d..c909e7efd90 100644 --- a/spec/lib/sidebars/groups/super_sidebar_menus/operations_menu_spec.rb +++ b/spec/lib/sidebars/groups/super_sidebar_menus/operations_menu_spec.rb @@ -16,7 +16,6 @@ RSpec.describe Sidebars::Groups::SuperSidebarMenus::OperationsMenu, feature_cate expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem]) expect(items.map(&:item_id)).to eq([ :dependency_proxy, - :container_registry, :group_kubernetes_clusters ]) end diff --git a/spec/migrations/20230804053643_add_ticket_work_item_type_spec.rb b/spec/migrations/20230804053643_add_ticket_work_item_type_spec.rb new file mode 100644 index 00000000000..9a6eeb44254 --- /dev/null +++ b/spec/migrations/20230804053643_add_ticket_work_item_type_spec.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddTicketWorkItemType, :migration, feature_category: :service_desk do + include MigrationHelpers::WorkItemTypesHelper + + let(:work_item_types) { table(:work_item_types) } + let(:work_item_widget_definitions) { table(:work_item_widget_definitions) } + let(:work_item_hierarchy_restrictions) { table(:work_item_hierarchy_restrictions) } + let(:base_types) do + { + issue: 0, + incident: 1, + test_case: 2, + requirement: 3, + task: 4, + objective: 5, + key_result: 6, + epic: 7, + ticket: 8 + } + end + + after(:all) do + # Make sure base types are recreated after running the migration + # because migration specs are not run in a transaction + reset_work_item_types + end + + before do + reset_db_state_prior_to_migration + end + + it 'adds the ticket type, widget definitions and hierarchy restrictions', :aggregate_failures do + expect do + migrate! + end.to change { work_item_types.count }.by(1) + .and(change { work_item_widget_definitions.count }.by(13)) + .and(change { work_item_hierarchy_restrictions.count }.by(2)) + + ticket_type = work_item_types.last + issue_type = work_item_types.find_by!(namespace_id: nil, base_type: base_types[:issue]) + + expect(work_item_types.pluck(:base_type)).to include(base_types[:ticket]) + expect( + work_item_widget_definitions.where(work_item_type_id: ticket_type.id).pluck(:widget_type) + ).to match_array(described_class::TICKET_WIDGETS.values) + expect( + work_item_hierarchy_restrictions.where(parent_type_id: ticket_type.id).pluck(:child_type_id, :maximum_depth) + ).to contain_exactly([ticket_type.id, 1], [issue_type.id, 1]) + end + + it "skips creating the new type and it's definitions when it already exists" do + work_item_types.find_or_create_by!( + name: 'Ticket', namespace_id: nil, base_type: base_types[:ticket], icon_name: 'issue-type-issue' + ) + + expect do + migrate! + end.to not_change(work_item_types, :count) + .and(not_change(work_item_widget_definitions, :count)) + .and(not_change(work_item_hierarchy_restrictions, :count)) + end + + it "skips creating the new type and it's definitions when type creation fails" do + allow(described_class::MigrationWorkItemType).to receive(:create) + .and_return(described_class::MigrationWorkItemType.new) + + expect do + migrate! + end.to not_change(work_item_types, :count) + .and(not_change(work_item_widget_definitions, :count)) + .and(not_change(work_item_hierarchy_restrictions, :count)) + end + + def reset_db_state_prior_to_migration + # Database needs to be in a similar state as when this migration was created + work_item_types.delete_all + + { + issue: { name: 'Issue', icon_name: 'issue-type-issue' }, + incident: { name: 'Incident', icon_name: 'issue-type-incident' }, + test_case: { name: 'Test Case', icon_name: 'issue-type-test-case' }, + requirement: { name: 'Requirement', icon_name: 'issue-type-requirements' }, + task: { name: 'Task', icon_name: 'issue-type-task' }, + objective: { name: 'Objective', icon_name: 'issue-type-objective' }, + key_result: { name: 'Key Result', icon_name: 'issue-type-keyresult' }, + epic: { name: 'Epic', icon_name: 'issue-type-epic' } + }.each do |type, opts| + work_item_types.find_or_create_by!( + name: opts[:name], namespace_id: nil, base_type: base_types[type], icon_name: opts[:icon_name] + ) + end + end +end diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb index 83c233fa942..498af80dbb6 100644 --- a/spec/models/ci/job_artifact_spec.rb +++ b/spec/models/ci/job_artifact_spec.rb @@ -824,4 +824,82 @@ RSpec.describe Ci::JobArtifact, feature_category: :build_artifacts do it { is_expected.to eq(artifact.file.filename) } end + + describe '#to_deleted_object_attrs' do + let(:pick_up_at) { nil } + let(:expire_at) { nil } + let(:file_final_path) { nil } + + let(:artifact) do + create( + :ci_job_artifact, + :archive, + :remote_store, + file_final_path: file_final_path, + expire_at: expire_at + ) + end + + subject(:attributes) { artifact.to_deleted_object_attrs(pick_up_at) } + + before do + stub_artifacts_object_storage + end + + shared_examples_for 'returning attributes for object deletion' do + it 'returns the file store' do + expect(attributes[:file_store]).to eq(artifact.file_store) + end + + context 'when pick_up_at is present' do + let(:pick_up_at) { 2.hours.ago } + + it 'returns the pick_up_at value' do + expect(attributes[:pick_up_at]).to eq(pick_up_at) + end + end + + context 'when pick_up_at is not present' do + context 'and expire_at is present' do + let(:expire_at) { 4.hours.ago } + + it 'sets expire_at as pick_up_at' do + expect(attributes[:pick_up_at]).to eq(expire_at) + end + end + + context 'and expire_at is not present' do + it 'sets current time as pick_up_at' do + freeze_time do + expect(attributes[:pick_up_at]).to eq(Time.current) + end + end + end + end + end + + context 'when file_final_path is present' do + let(:file_final_path) { 'some/hash/path/to/randomfile' } + + it 'returns the store_dir and file based on the file_final_path' do + expect(attributes).to include( + store_dir: 'some/hash/path/to', + file: 'randomfile' + ) + end + + it_behaves_like 'returning attributes for object deletion' + end + + context 'when file_final_path is not present' do + it 'returns the uploader default store_dir and file_identifier' do + expect(attributes).to include( + store_dir: artifact.file.store_dir.to_s, + file: artifact.file_identifier + ) + end + + it_behaves_like 'returning attributes for object deletion' + end + end end diff --git a/spec/models/work_items/type_spec.rb b/spec/models/work_items/type_spec.rb index 024157731a9..e4d2ccdfc5a 100644 --- a/spec/models/work_items/type_spec.rb +++ b/spec/models/work_items/type_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe WorkItems::Type do +RSpec.describe WorkItems::Type, feature_category: :team_planning do describe 'modules' do it { is_expected.to include_module(CacheMarkdownField) } end @@ -49,10 +49,10 @@ RSpec.describe WorkItems::Type do it 'deletes type but not unrelated issues' do type = create(:work_item_type) - expect(described_class.count).to eq(9) + expect(described_class.count).to eq(10) expect { type.destroy! }.not_to change(Issue, :count) - expect(described_class.count).to eq(8) + expect(described_class.count).to eq(9) end end diff --git a/spec/support/shared_examples/work_item_hierarchy_restrictions_importer.rb b/spec/support/shared_examples/work_item_hierarchy_restrictions_importer.rb index 641b05debe6..d61458db3b3 100644 --- a/spec/support/shared_examples/work_item_hierarchy_restrictions_importer.rb +++ b/spec/support/shared_examples/work_item_hierarchy_restrictions_importer.rb @@ -3,7 +3,7 @@ RSpec.shared_examples 'work item hierarchy restrictions importer' do shared_examples_for 'adds restrictions' do it "adds all restrictions if they don't exist" do - expect { subject }.to change { WorkItems::HierarchyRestriction.count }.from(0).to(6) + expect { subject }.to change { WorkItems::HierarchyRestriction.count }.from(0).to(7) end end @@ -53,7 +53,7 @@ RSpec.shared_examples 'work item hierarchy restrictions importer' do expect { subject }.to make_queries_matching(/INSERT/, 1).and( change { WorkItems::HierarchyRestriction.count }.by(1) ) - expect(WorkItems::HierarchyRestriction.count).to eq(6) + expect(WorkItems::HierarchyRestriction.count).to eq(7) end end end diff --git a/vendor/gems/sidekiq-reliable-fetch/lib/sidekiq/semi_reliable_fetch.rb b/vendor/gems/sidekiq-reliable-fetch/lib/sidekiq/semi_reliable_fetch.rb index 5b8a601dde1..d33b5049300 100644 --- a/vendor/gems/sidekiq-reliable-fetch/lib/sidekiq/semi_reliable_fetch.rb +++ b/vendor/gems/sidekiq-reliable-fetch/lib/sidekiq/semi_reliable_fetch.rb @@ -10,6 +10,11 @@ module Sidekiq def initialize(options) super + @alternative_store = options[:alternative_store] + @namespace = options[:namespace] + + @queues = @queues + @queues.map { |q| "#{@namespace}:#{q}" } if @namespace + if strictly_ordered_queues @queues = @queues.uniq @queues << { timeout: semi_reliable_fetch_timeout } @@ -19,10 +24,12 @@ module Sidekiq private def retrieve_unit_of_work - work = Sidekiq.redis { |conn| conn.brpop(*queues_cmd) } + work = with_redis { |conn| conn.brpop(*queues_cmd) } return unless work - unit_of_work = UnitOfWork.new(*work) + queue, job = work + queue = queue.to_s.sub(/\A#{@namespace}:/, '') if @namespace + unit_of_work = UnitOfWork.new(queue, job) Sidekiq.redis do |conn| conn.lpush(self.class.working_queue_name(unit_of_work.queue), unit_of_work.job) @@ -31,6 +38,14 @@ module Sidekiq unit_of_work end + def with_redis(&blk) + if @alternative_store + @alternative_store.with(&blk) + else + Sidekiq.redis(&blk) + end + end + def queues_cmd if strictly_ordered_queues @queues diff --git a/vendor/gems/sidekiq-reliable-fetch/spec/semi_reliable_fetch_spec.rb b/vendor/gems/sidekiq-reliable-fetch/spec/semi_reliable_fetch_spec.rb index 84a0203b683..d6701c7c7e1 100644 --- a/vendor/gems/sidekiq-reliable-fetch/spec/semi_reliable_fetch_spec.rb +++ b/vendor/gems/sidekiq-reliable-fetch/spec/semi_reliable_fetch_spec.rb @@ -7,10 +7,45 @@ describe Sidekiq::SemiReliableFetch do include_examples 'a Sidekiq fetcher' describe '#retrieve_work' do - context 'timeout config' do - let(:queues) { ['stuff_to_do'] } - let(:fetcher) { described_class.new(queues: queues) } + let(:queues) { ['stuff_to_do'] } + let(:options) { { queues: queues } } + let(:fetcher) { described_class.new(options) } + + context 'namespace config' do + let(:options) { { queues: queues, namespace: 'namespaced' } } + + before do + Sidekiq.redis do |conn| + conn.rpush('queue:stuff_to_do', 'msg1') + conn.rpush('namespaced:queue:stuff_to_do', 'msg2') + end + end + + it 'runs brpop on both namespaced and non-namespaced' do + jobs = (1..2).map { fetcher.retrieve_work&.job } + + expect(jobs).to match_array(['msg1', 'msg2']) + end + end + context 'alternative_store config' do + let(:store) { Sidekiq::RedisConnection.create(url: REDIS_URL, size: 10) } + let(:options) { { queues: queues, alternative_store: store } } + + it 'connects using alternative store' do + Sidekiq.redis do |connection| + expect(connection).not_to receive(:brpop) + end + + store.with do |connection| + expect(connection).to receive(:brpop).with("queue:stuff_to_do", { timeout: 2 }).once.and_call_original + end + + fetcher.retrieve_work + end + end + + context 'timeout config' do before do stub_env('SIDEKIQ_SEMI_RELIABLE_FETCH_TIMEOUT', timeout) end |