diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index ba42bbc9507..95780116800 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -685,37 +685,31 @@ rspec-ee unit pg12 opensearch1: extends: - .rspec-ee-base-pg12-opensearch1 - .rspec-ee-unit-parallel - - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only rspec-ee unit pg12 opensearch2: extends: - .rspec-ee-base-pg12-opensearch2 - .rspec-ee-unit-parallel - - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only rspec-ee integration pg12 opensearch1: extends: - .rspec-ee-base-pg12-opensearch1 - .rspec-ee-integration-parallel - - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only rspec-ee integration pg12 opensearch2: extends: - .rspec-ee-base-pg12-opensearch2 - .rspec-ee-integration-parallel - - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only rspec-ee system pg12 opensearch1: extends: - .rspec-ee-base-pg12-opensearch1 - .rspec-ee-system-parallel - - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only rspec-ee system pg12 opensearch2: extends: - .rspec-ee-base-pg12-opensearch2 - .rspec-ee-system-parallel - - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only # PG13 rspec-ee migration pg13: diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index b09fd5e2aa6..489d72b2f7e 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -620,6 +620,7 @@ .rails:rules:run-search-tests: rules: + - !reference [".rails:rules:default-branch-schedule-nightly--code-backstage-ee-only", rules] - <<: *if-merge-request-labels-group-global-search changes: *search-backend-patterns - <<: *if-merge-request-labels-group-global-search diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index fae1f43bf1c..fa35093a0a3 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -8eb2d65be9607663316e0939d2550fa22df98ea0 +6d7521c579ecb1b0a76c4c29e12ce9b72dd4057e diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue index bd4f2960269..8726cd2f6fa 100644 --- a/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue +++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue @@ -19,9 +19,13 @@ export default { return { initialFilterValue: [], initialSortBy: DEFAULT_SORT, - tokens: [...FILTERED_SEARCH_TOKENS, buildFilteredSearchCategoryToken(this.categories)], }; }, + computed: { + tokens() { + return [...FILTERED_SEARCH_TOKENS, buildFilteredSearchCategoryToken(this.categories)]; + }, + }, created() { const query = queryToObject(window.location.search); diff --git a/app/assets/javascripts/admin/abuse_reports/constants.js b/app/assets/javascripts/admin/abuse_reports/constants.js index 2db107923f6..ee2e9ab2cbf 100644 --- a/app/assets/javascripts/admin/abuse_reports/constants.js +++ b/app/assets/javascripts/admin/abuse_reports/constants.js @@ -23,6 +23,12 @@ export const FILTERED_SEARCH_TOKEN_USER = { defaultUsers: [], }; +export const FILTERED_SEARCH_TOKEN_REPORTER = { + ...FILTERED_SEARCH_TOKEN_USER, + type: 'reporter', + title: __('Reporter'), +}; + export const FILTERED_SEARCH_TOKEN_STATUS = { type: 'status', icon: 'status', @@ -68,4 +74,8 @@ export const FILTERED_SEARCH_TOKEN_CATEGORY = { operators: OPERATORS_IS, }; -export const FILTERED_SEARCH_TOKENS = [FILTERED_SEARCH_TOKEN_USER, FILTERED_SEARCH_TOKEN_STATUS]; +export const FILTERED_SEARCH_TOKENS = [ + FILTERED_SEARCH_TOKEN_USER, + FILTERED_SEARCH_TOKEN_REPORTER, + FILTERED_SEARCH_TOKEN_STATUS, +]; diff --git a/app/assets/javascripts/blame/streaming/index.js b/app/assets/javascripts/blame/streaming/index.js index a74e01b6423..935343cca2e 100644 --- a/app/assets/javascripts/blame/streaming/index.js +++ b/app/assets/javascripts/blame/streaming/index.js @@ -1,6 +1,6 @@ import { renderHtmlStreams } from '~/streaming/render_html_streams'; import { handleStreamedAnchorLink } from '~/streaming/handle_streamed_anchor_link'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { __ } from '~/locale'; import { rateLimitStreamRequests } from '~/streaming/rate_limit_stream_requests'; import { toPolyfillReadable } from '~/streaming/polyfills'; diff --git a/app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue b/app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue index 5411a4a5ae3..f9bf262bcac 100644 --- a/app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue +++ b/app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue @@ -1,6 +1,6 @@ + diff --git a/app/assets/javascripts/environments/components/kubernetes_overview.vue b/app/assets/javascripts/environments/components/kubernetes_overview.vue new file mode 100644 index 00000000000..cfb18cc4f82 --- /dev/null +++ b/app/assets/javascripts/environments/components/kubernetes_overview.vue @@ -0,0 +1,73 @@ + + diff --git a/app/assets/javascripts/environments/components/new_environment_item.vue b/app/assets/javascripts/environments/components/new_environment_item.vue index 73dfd993c5b..2ec6e12b8b3 100644 --- a/app/assets/javascripts/environments/components/new_environment_item.vue +++ b/app/assets/javascripts/environments/components/new_environment_item.vue @@ -11,6 +11,7 @@ import { import { __, s__ } from '~/locale'; import { truncate } from '~/lib/utils/text_utility'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import isLastDeployment from '../graphql/queries/is_last_deployment.query.graphql'; import ExternalUrl from './environment_external_url.vue'; import Actions from './environment_actions.vue'; @@ -22,6 +23,7 @@ import Terminal from './environment_terminal_button.vue'; import Delete from './environment_delete.vue'; import Deployment from './deployment.vue'; import DeployBoardWrapper from './deploy_board_wrapper.vue'; +import KubernetesOverview from './kubernetes_overview.vue'; export default { components: { @@ -42,6 +44,7 @@ export default { Terminal, TimeAgoTooltip, Delete, + KubernetesOverview, EnvironmentAlert: () => import('ee_component/environments/components/environment_alert.vue'), EnvironmentApproval: () => import('ee_component/environments/components/environment_approval.vue'), @@ -49,6 +52,7 @@ export default { directives: { GlTooltip, }, + mixins: [glFeatureFlagsMixin()], inject: ['helpPagePath'], props: { environment: { @@ -162,6 +166,18 @@ export default { rolloutStatus() { return this.environment?.rolloutStatus; }, + agent() { + return this.environment?.agent || {}; + }, + isKubernetesOverviewAvailable() { + return this.glFeatures?.kasUserAccessProject; + }, + hasRequiredAgentData() { + return this.agent.project && this.agent.id && this.agent.name; + }, + showKubernetesOverview() { + return this.isKubernetesOverviewAvailable && this.hasRequiredAgentData; + }, }, methods: { toggleCollapse() { @@ -184,6 +200,13 @@ export default { 'gl-md-pl-7', 'gl-bg-gray-10', ], + kubernetesOverviewClasses: [ + 'gl-border-gray-100', + 'gl-border-t-solid', + 'gl-border-1', + 'gl-py-4', + 'gl-bg-gray-10', + ], }; +
+ +
import { GlLoadingIcon } from '@gitlab/ui'; import { fetchPolicies } from '~/lib/graphql'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { __ } from '~/locale'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import { TYPE_USERS_SAVED_REPLY } from '~/graphql_shared/constants'; diff --git a/app/assets/stylesheets/highlight/diff_custom_colors_addition.scss b/app/assets/stylesheets/highlight/diff_custom_colors_addition.scss index 30895a55711..5f195bc47bf 100644 --- a/app/assets/stylesheets/highlight/diff_custom_colors_addition.scss +++ b/app/assets/stylesheets/highlight/diff_custom_colors_addition.scss @@ -25,7 +25,7 @@ } } - .gd { + .gi { background-color: var(--diff-addition-color); } } diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb index 61e32650db3..047c273969c 100644 --- a/app/controllers/import/gitea_controller.rb +++ b/app/controllers/import/gitea_controller.rb @@ -71,6 +71,11 @@ class Import::GiteaController < Import::GithubController end end + override :serialized_imported_projects + def serialized_imported_projects(projects = already_added_projects) + ProjectSerializer.new.represent(projects, serializer: :import, provider_url: provider_url) + end + override :client_repos def client_repos @client_repos ||= filtered(client.repos) diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index 2729b11fcff..d164809777c 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -145,7 +145,10 @@ class Import::GithubController < Import::BaseController end def serialized_imported_projects(projects = already_added_projects) - ProjectSerializer.new.represent(projects, serializer: :import, provider_url: provider_url) + ProjectSerializer.new.represent( + projects, + serializer: :import, provider_url: provider_url, client: client_proxy + ) end def expire_etag_cache diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index 130456306aa..ad498a4ac86 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -20,6 +20,10 @@ class Projects::EnvironmentsController < Projects::ApplicationController push_frontend_feature_flag(:environment_details_vue, @project) end + before_action only: [:index] do + push_frontend_feature_flag(:kas_user_access_project, @project) + end + before_action :authorize_read_environment!, except: [:metrics, :additional_metrics, :metrics_dashboard, :metrics_redirect] before_action :authorize_create_environment!, only: [:new, :create] before_action :authorize_stop_environment!, only: [:stop] diff --git a/app/models/bulk_imports/file_transfer.rb b/app/models/bulk_imports/file_transfer.rb index 5be954b98da..c6af4e0c833 100644 --- a/app/models/bulk_imports/file_transfer.rb +++ b/app/models/bulk_imports/file_transfer.rb @@ -9,9 +9,9 @@ module BulkImports def config_for(portable) case portable when ::Project - FileTransfer::ProjectConfig.new(portable) + ::BulkImports::FileTransfer::ProjectConfig.new(portable) when ::Group - FileTransfer::GroupConfig.new(portable) + ::BulkImports::FileTransfer::GroupConfig.new(portable) else raise(UnsupportedObjectType, "Unsupported object type: #{portable.class}") end diff --git a/app/models/ci/catalog/listing.rb b/app/models/ci/catalog/listing.rb index 99a5230b64e..92464cb645f 100644 --- a/app/models/ci/catalog/listing.rb +++ b/app/models/ci/catalog/listing.rb @@ -7,21 +7,28 @@ module Ci # CI/CD Catalog given a namespace as a scope. # This model is not directly backed by a table and joins catalog resources # with projects to return relevant data. - def initialize(namespace) + def initialize(namespace, current_user) raise ArgumentError, 'Namespace is not a root namespace' unless namespace.root? @namespace = namespace + @current_user = current_user end def resources Ci::Catalog::Resource .joins(:project).includes(:project) - .merge(Project.in_namespace(namespace.self_and_descendant_ids)) + .merge(projects_in_namespace_visible_to_user) end private - attr_reader :namespace + attr_reader :namespace, :current_user + + def projects_in_namespace_visible_to_user + Project + .in_namespace(namespace.self_and_descendant_ids) + .public_or_visible_to_user(current_user) + end end end end diff --git a/app/models/concerns/counter_attribute.rb b/app/models/concerns/counter_attribute.rb index 58ea57962c5..d7ee533b53c 100644 --- a/app/models/concerns/counter_attribute.rb +++ b/app/models/concerns/counter_attribute.rb @@ -5,7 +5,7 @@ # after a period of time (10 minutes). # When an attribute is incremented by a value, the increment is added # to a Redis key. Then, FlushCounterIncrementsWorker will execute -# `flush_increments_to_database!` which removes increments from Redis for a +# `commit_increment!` which removes increments from Redis for a # given model attribute and updates the values in the database. # # @example: @@ -29,8 +29,24 @@ # counter_attribute :conditional_one, if: -> { |object| object.use_counter_attribute? } # end # +# The `counter_attribute` by default will return last persisted value. +# It's possible to always return accurate (real) value instead by using `returns_current: true`. +# While doing this the `counter_attribute` will overwrite attribute accessor to fetch +# the buffered information added to the last persisted value. This will incur cost a Redis call per attribute fetched. +# +# @example: +# +# class ProjectStatistics +# include CounterAttribute +# +# counter_attribute :commit_count, returns_current: true +# end +# +# in that case +# model.commit_count => persisted value + buffered amount to be added +# # To increment the counter we can use the method: -# increment_counter(:commit_count, 3) +# increment_amount(:commit_count, 3) # # This method would determine whether it would increment the counter using Redis, # or fallback to legacy increment on ActiveRecord counters. @@ -50,11 +66,22 @@ module CounterAttribute include Gitlab::Utils::StrongMemoize class_methods do - def counter_attribute(attribute, if: nil) + def counter_attribute(attribute, if: nil, returns_current: false) counter_attributes << { attribute: attribute, - if_proc: binding.local_variable_get(:if) # can't read `if` directly + if_proc: binding.local_variable_get(:if), # can't read `if` directly + returns_current: returns_current } + + if returns_current + define_method(attribute) do + current_counter(attribute) + end + end + + define_method("increment_#{attribute}") do |amount| + increment_amount(attribute, amount) + end end def counter_attributes @@ -87,6 +114,15 @@ module CounterAttribute end end + def increment_amount(attribute, amount) + counter = Gitlab::Counters::Increment.new(amount: amount) + increment_counter(attribute, counter) + end + + def current_counter(attribute) + read_attribute(attribute) + counter(attribute).get + end + def increment_counter(attribute, increment) return if increment.amount == 0 @@ -172,7 +208,8 @@ module CounterAttribute Gitlab::AppLogger.info( message: 'Acquiring lease for project statistics update', - project_statistics_id: id, + model: self.class.name, + model_id: id, project_id: project.id, **log_fields, **Gitlab::ApplicationContext.current @@ -184,7 +221,8 @@ module CounterAttribute rescue Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError Gitlab::AppLogger.warn( message: 'Concurrent project statistics update detected', - project_statistics_id: id, + model: self.class.name, + model_id: id, project_id: project.id, **log_fields, **Gitlab::ApplicationContext.current diff --git a/app/models/concerns/web_hooks/auto_disabling.rb b/app/models/concerns/web_hooks/auto_disabling.rb index 5f9901901d4..44e4c436625 100644 --- a/app/models/concerns/web_hooks/auto_disabling.rb +++ b/app/models/concerns/web_hooks/auto_disabling.rb @@ -8,11 +8,17 @@ module WebHooks class_methods do def auto_disabling_enabled? - ENABLED_HOOK_TYPES.include?(name) && + enabled_hook_types.include?(name) && Gitlab::SafeRequestStore.fetch(:auto_disabling_web_hooks) do Feature.enabled?(:auto_disabling_web_hooks, type: :ops) end end + + private + + def enabled_hook_types + ENABLED_HOOK_TYPES + end end included do @@ -135,3 +141,6 @@ module WebHooks end end end + +WebHooks::AutoDisabling.prepend_mod +WebHooks::AutoDisabling::ClassMethods.prepend_mod diff --git a/app/models/project.rb b/app/models/project.rb index 3053a47ca0a..50fad2c210d 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -2832,7 +2832,7 @@ class Project < ApplicationRecord end def all_protected_branches - if Feature.enabled?(:group_protected_branches) + if Feature.enabled?(:group_protected_branches, group) @all_protected_branches ||= ProtectedBranch.from_union([protected_branches, group_protected_branches]) else protected_branches diff --git a/app/models/projects/data_transfer.rb b/app/models/projects/data_transfer.rb index a93aea55781..faab0bb6db2 100644 --- a/app/models/projects/data_transfer.rb +++ b/app/models/projects/data_transfer.rb @@ -4,6 +4,9 @@ # This class ensures that we keep 1 record per project per month. module Projects class DataTransfer < ApplicationRecord + include AfterCommitQueue + include CounterAttribute + self.table_name = 'project_data_transfers' belongs_to :project @@ -11,6 +14,11 @@ module Projects scope :current_month, -> { where(date: beginning_of_month) } + counter_attribute :repository_egress, returns_current: true + counter_attribute :artifacts_egress, returns_current: true + counter_attribute :packages_egress, returns_current: true + counter_attribute :registry_egress, returns_current: true + def self.beginning_of_month(time = Time.current) time.utc.beginning_of_month end diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb index ac42b3febc6..22eaac94897 100644 --- a/app/models/protected_branch.rb +++ b/app/models/protected_branch.rb @@ -43,7 +43,7 @@ class ProtectedBranch < ApplicationRecord end def self.allow_force_push?(project, ref_name) - if Feature.enabled?(:group_protected_branches) + if Feature.enabled?(:group_protected_branches, project.group) protected_branches = project.all_protected_branches.matching(ref_name) project_protected_branches, group_protected_branches = protected_branches.partition(&:project_id) @@ -67,11 +67,7 @@ class ProtectedBranch < ApplicationRecord end def self.protected_refs(project) - if Feature.enabled?(:group_protected_branches) - project.all_protected_branches - else - project.protected_branches - end + project.all_protected_branches end # overridden in EE diff --git a/app/models/repository.rb b/app/models/repository.rb index 301189d5109..01f3d402b0a 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -48,7 +48,7 @@ class Repository # For example, for entry `:commit_count` there's a method called `commit_count` which # stores its data in the `commit_count` cache key. CACHED_METHODS = %i(size commit_count readme_path contribution_guide - changelog license_blob license_licensee license_gitaly gitignore + changelog license_blob license_gitaly gitignore gitlab_ci_yml branch_names tag_names branch_count tag_count avatar exists? root_ref merged_branch_names has_visible_content? issue_template_names_hash merge_request_template_names_hash @@ -60,7 +60,7 @@ class Repository METHOD_CACHES_FOR_FILE_TYPES = { readme: %i(readme_path), changelog: :changelog, - license: %i(license_blob license_licensee license_gitaly), + license: %i(license_blob license_gitaly), contributing: :contribution_guide, gitignore: :gitignore, gitlab_ci: :gitlab_ci_yml, @@ -656,24 +656,13 @@ class Repository end def license - if Feature.enabled?(:license_from_gitaly) - license_gitaly - else - license_licensee - end + license_gitaly end - def license_licensee - return unless exists? - - raw_repository.license(false) - end - cache_method :license_licensee - def license_gitaly return unless exists? - raw_repository.license(true) + raw_repository.license end cache_method :license_gitaly diff --git a/app/serializers/project_import_entity.rb b/app/serializers/project_import_entity.rb index 58360321f7c..302086143c1 100644 --- a/app/serializers/project_import_entity.rb +++ b/app/serializers/project_import_entity.rb @@ -16,4 +16,11 @@ class ProjectImportEntity < ProjectEntity expose :import_error, if: ->(project) { project.import_state&.failed? } do |project| project.import_failures.last&.exception_message end + + # Only for GitHub importer where we pass client through + expose :relation_type do |project, options| + next nil if options[:client].nil? || Feature.disabled?(:remove_legacy_github_client) + + ::Gitlab::GithubImport::ProjectRelationType.new(options[:client]).for(project.import_source) + end end diff --git a/app/services/projects/protect_default_branch_service.rb b/app/services/projects/protect_default_branch_service.rb index 5360902038b..0aca525921c 100644 --- a/app/services/projects/protect_default_branch_service.rb +++ b/app/services/projects/protect_default_branch_service.rb @@ -45,11 +45,7 @@ module Projects end def protected_branch_exists? - if Feature.enabled?(:group_protected_branches) - project.all_protected_branches.find_by_name(default_branch).present? - else - project.protected_branches.find_by_name(default_branch).present? - end + project.all_protected_branches.find_by_name(default_branch).present? end def default_branch diff --git a/app/services/protected_branches/cache_service.rb b/app/services/protected_branches/cache_service.rb index 4a9fc335421..ac02bf25617 100644 --- a/app/services/protected_branches/cache_service.rb +++ b/app/services/protected_branches/cache_service.rb @@ -73,7 +73,8 @@ module ProtectedBranches end def redis_key - @redis_key ||= if Feature.enabled?(:group_protected_branches) + group = project_or_group.is_a?(Group) ? project_or_group : project_or_group.group + @redis_key ||= if Feature.enabled?(:group_protected_branches, group) [CACHE_ROOT_KEY, project_or_group.class.name, project_or_group.id].join(':') else [CACHE_ROOT_KEY, project_or_group.id].join(':') diff --git a/app/views/admin/application_settings/appearances/_form.html.haml b/app/views/admin/application_settings/appearances/_form.html.haml index 6c6334905ca..1b0e974a0ca 100644 --- a/app/views/admin/application_settings/appearances/_form.html.haml +++ b/app/views/admin/application_settings/appearances/_form.html.haml @@ -16,7 +16,8 @@ = image_tag @appearance.header_logo_path, class: 'appearance-light-logo-preview' - if @appearance.persisted? %br - = link_to _('Remove header logo'), header_logos_admin_application_settings_appearances_path, data: { confirm: _("Header logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove header logo') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm" + = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: header_logos_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Header logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove header logo') } }) do + = _('Remove header logo') %hr = f.hidden_field :header_logo_cache = f.file_field :header_logo, class: "", accept: 'image/*' @@ -35,7 +36,8 @@ = image_tag @appearance.favicon_path, class: 'appearance-light-logo-preview' - if @appearance.persisted? %br - = link_to _('Remove favicon'), favicon_admin_application_settings_appearances_path, data: { confirm: _("Favicon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove favicon') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm" + = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: favicon_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Favicon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove favicon') } }) do + = _('Remove favicon') %hr = f.hidden_field :favicon_cache = f.file_field :favicon, class: '', accept: 'image/*' @@ -67,7 +69,8 @@ = image_tag @appearance.logo_path, class: 'appearance-logo-preview' - if @appearance.persisted? %br - = link_to _('Remove logo'), logo_admin_application_settings_appearances_path, data: { confirm: _("Logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove logo') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm remove-logo" + = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: logo_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove logo') } }) do + = _('Remove logo') %hr = f.hidden_field :logo_cache = f.file_field :logo, class: "", accept: 'image/*' @@ -98,7 +101,8 @@ = image_tag @appearance.pwa_icon_path, class: 'appearance-pwa-icon-preview' - if @appearance.persisted? %br - = link_to _('Remove icon'), pwa_icon_admin_application_settings_appearances_path, data: { confirm: _("Icon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove icon') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm remove-logo" + = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: pwa_icon_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Icon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove icon') } }) do + = _('Remove icon') %hr = f.hidden_field :pwa_icon_cache = f.file_field :pwa_icon, class: "", accept: 'image/*' diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index b10d05efc4f..5f74a4c4427 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -17,6 +17,9 @@ = s_('Preferences|Color theme') %p = s_('Preferences|Customize the color of GitLab.') + - if show_super_sidebar? + %p + = s_('Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab\'s appearance.') .col-lg-8.application-theme .row - Gitlab::Themes.each do |theme| diff --git a/config/feature_flags/development/license_from_gitaly.yml b/config/feature_flags/development/license_from_gitaly.yml deleted file mode 100644 index ad79d56a8ab..00000000000 --- a/config/feature_flags/development/license_from_gitaly.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: license_from_gitaly -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77041 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/374300 -milestone: '15.5' -type: development -group: group::gitaly -default_enabled: false diff --git a/config/feature_flags/development/limited_capacity_seat_refresh_worker_high.yml b/config/feature_flags/development/limited_capacity_seat_refresh_worker_high.yml deleted file mode 100644 index 28f1c8a988e..00000000000 --- a/config/feature_flags/development/limited_capacity_seat_refresh_worker_high.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: limited_capacity_seat_refresh_worker_high -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104099 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382725 -milestone: '15.9' -type: development -group: group::utilization -default_enabled: false diff --git a/config/feature_flags/development/limited_capacity_seat_refresh_worker_low.yml b/config/feature_flags/development/limited_capacity_seat_refresh_worker_low.yml deleted file mode 100644 index a0b306ac792..00000000000 --- a/config/feature_flags/development/limited_capacity_seat_refresh_worker_low.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: limited_capacity_seat_refresh_worker_low -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104099 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382725 -milestone: '15.9' -type: development -group: group::utilization -default_enabled: false diff --git a/config/feature_flags/development/limited_capacity_seat_refresh_worker_medium.yml b/config/feature_flags/development/limited_capacity_seat_refresh_worker_medium.yml deleted file mode 100644 index 1df482e0624..00000000000 --- a/config/feature_flags/development/limited_capacity_seat_refresh_worker_medium.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: limited_capacity_seat_refresh_worker_medium -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104099 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382725 -milestone: '15.9' -type: development -group: group::utilization -default_enabled: false diff --git a/config/vue3migration/compiler.js b/config/vue3migration/compiler.js new file mode 100644 index 00000000000..bb92e1e2356 --- /dev/null +++ b/config/vue3migration/compiler.js @@ -0,0 +1,50 @@ +const { parse, compile: compilerDomCompile } = require('@vue/compiler-dom'); + +const getPropIndex = (node, prop) => node.props?.findIndex((p) => p.name === prop) ?? -1; + +function modifyKeysInsideTemplateTag(templateNode) { + let keyCandidate = null; + for (const node of templateNode.children) { + const keyBindingIndex = node.props + ? node.props.findIndex((prop) => prop.arg && prop.arg.content === 'key') + : -1; + + if (keyBindingIndex !== -1 && getPropIndex(node, 'for') === -1) { + if (!keyCandidate) { + keyCandidate = node.props[keyBindingIndex]; + } + node.props.splice(keyBindingIndex, 1); + } + } + + if (keyCandidate) { + templateNode.props.push(keyCandidate); + } +} + +module.exports = { + parse, + compile(template, options) { + const rootNode = parse(template, options); + const pendingNodes = [rootNode]; + while (pendingNodes.length) { + const currentNode = pendingNodes.pop(); + if (getPropIndex(currentNode, 'for') !== -1) { + if (currentNode.tag === 'template') { + // This one will be dropped all together with compiler when we drop Vue.js 2 support + modifyKeysInsideTemplateTag(currentNode); + } + + // This one will be dropped when https://github.com/vuejs/core/issues/7725 will be fixed + const vOncePropIndex = getPropIndex(currentNode, 'once'); + if (vOncePropIndex !== -1) { + currentNode.props.splice(vOncePropIndex, 1); + } + } + + currentNode.children?.forEach((child) => pendingNodes.push(child)); + } + + return compilerDomCompile(rootNode, options); + }, +}; diff --git a/config/webpack.config.js b/config/webpack.config.js index e60440e74b3..8e218184f20 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -195,9 +195,6 @@ const alias = { ROOT_PATH, 'app/assets/javascripts/sentry/sentry_browser_wrapper.js', ), - // temporary alias until we replace all `flash` imports for `alert` - // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109449 - '~/flash': path.join(ROOT_PATH, 'app/assets/javascripts/alert.js'), '~': path.join(ROOT_PATH, 'app/assets/javascripts'), emojis: path.join(ROOT_PATH, 'fixtures/emojis'), empty_states: path.join(ROOT_PATH, 'app/views/shared/empty_states'), @@ -301,12 +298,15 @@ if (WEBPACK_USE_ESBUILD_LOADER) { } const vueLoaderOptions = { + ident: 'vue-loader-options', + cacheDirectory: path.join(CACHE_PATH, 'vue-loader'), cacheIdentifier: [ process.env.NODE_ENV || 'development', webpack.version, VUE_VERSION, VUE_LOADER_VERSION, + EXPLICIT_VUE_VERSION, ].join('|'), }; @@ -334,6 +334,8 @@ if (USE_VUE3) { Object.assign(alias, { vue: '@vue/compat', }); + + vueLoaderOptions.compiler = require.resolve('./vue3migration/compiler'); } module.exports = { diff --git a/data/deprecations/15-9-trigger-job-status.yml b/data/deprecations/15-9-trigger-job-status.yml index 66681de7f56..fb9d93bfb81 100644 --- a/data/deprecations/15-9-trigger-job-status.yml +++ b/data/deprecations/15-9-trigger-job-status.yml @@ -19,13 +19,13 @@ # - title: "Trigger jobs can mirror downstream pipeline status exactly" # (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." announcement_milestone: "15.9" # (required) The milestone when this feature was first announced as deprecated. - removal_milestone: "16.0" # (required) The milestone when this feature is planned to be removed + removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed breaking_change: true # (required) Change to false if this is not a breaking change. reporter: dhershkovitch # (required) GitLab username of the person reporting the change stage: verify # (required) String value of the stage that the feature was created in. e.g., Growth issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/285493 # (required) Link to the deprecation issue in GitLab body: | # (required) Do not modify this line, instead modify the lines below. - In some cases, like when a downstream pipeline had the `passed with warnings` status, trigger jobs that were using [`strategy: depend`](https://docs.gitlab.com/ee/ci/yaml/index.html#strategydepend) did not mirror the status of the downstream pipeline exactly. In GitLab 16.0 trigger jobs will show the exact same status as the the downstream pipeline. If your pipeline relied on this behavior, you should update your pipeline to handle the more accurate status. + In some cases, like when a downstream pipeline had the `passed with warnings` status, trigger jobs that were using [`strategy: depend`](https://docs.gitlab.com/ee/ci/yaml/index.html#strategydepend) did not mirror the status of the downstream pipeline exactly. In GitLab 17.0 trigger jobs will show the exact same status as the the downstream pipeline. If your pipeline relied on this behavior, you should update your pipeline to handle the more accurate status. # # OPTIONAL END OF SUPPORT FIELDS # diff --git a/doc/api/audit_events.md b/doc/api/audit_events.md index fec719b189c..f42ace8c1de 100644 --- a/doc/api/audit_events.md +++ b/doc/api/audit_events.md @@ -253,13 +253,16 @@ Example response: ## Project Audit Events -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/219238) in GitLab 13.1. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/219238) in GitLab 13.1. +> - [Support for keyset pagination added](https://gitlab.com/gitlab-org/gitlab/-/issues/367528) in GitLab 15.10. The Project Audit Events API allows you to retrieve [project audit events](../administration/audit_events.md#project-events). A user with a Maintainer role (or above) can retrieve project audit events of all users. A user with a Developer role is limited to project audit events based on their individual actions. +When requesting consecutive pages of results, you should use [keyset pagination](rest/index.md#keyset-based-pagination). + ### Retrieve all project audit events ```plaintext diff --git a/doc/api/rest/index.md b/doc/api/rest/index.md index ca335bfc12e..91a70c3f2a9 100644 --- a/doc/api/rest/index.md +++ b/doc/api/rest/index.md @@ -483,12 +483,13 @@ pagination headers. Keyset-based pagination is supported only for selected resources and ordering options: -| Resource | Options | Availability | -|:---------------------------------------------------------|:---------------------------------|:-------------------------------------------------------------------------------------------------------------| -| [Projects](../projects.md) | `order_by=id` only | Authenticated and unauthenticated users | -| [Groups](../groups.md) | `order_by=name`, `sort=asc` only | Unauthenticated users only | -| [Group audit events](../audit_events.md#group-audit-events) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/333968) in GitLab 15.2) | -| [Jobs](../jobs.md) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/362172) in GitLab 15.9) | +| Resource | Options | Availability | +|:----------------------------------------------------------------|:---------------------------------|:--------------------------------------------------------------------------------------------------------------| +| [Projects](../projects.md) | `order_by=id` only | Authenticated and unauthenticated users | +| [Groups](../groups.md) | `order_by=name`, `sort=asc` only | Unauthenticated users only | +| [Group audit events](../audit_events.md#group-audit-events) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/333968) in GitLab 15.2) | +| [Project audit events](../audit_events.md#project-audit-events) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367528) in GitLab 15.10) | +| [Jobs](../jobs.md) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/362172) in GitLab 15.9) | ### Pagination response headers diff --git a/doc/ci/secrets/id_token_authentication.md b/doc/ci/secrets/id_token_authentication.md index 0eb85a94b58..b10763b40d6 100644 --- a/doc/ci/secrets/id_token_authentication.md +++ b/doc/ci/secrets/id_token_authentication.md @@ -45,7 +45,7 @@ The following fields are included in each ID token: | [`iss`](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.1) | Always | Issuer of the token, which is the domain of the GitLab instance ("issuer" claim). | | [`jti`](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.7) | Always | Unique identifier for the token ("JWT ID" claim). | | [`nbf`](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.5) | Always | The time after which the token becomes valid ("not before" claim). | -| [`sub`](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.2) | Always | The job ID ("subject" claim). | +| [`sub`](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.2) | Always | `project_path:{group}/{project}:ref_type:{type}:ref:{branch_name}` ("subject" claim). | | `deployment_tier` | Job specifies an environment | [Deployment tier](../environments/index.md#deployment-tier-of-environments) of the environment the job specifies. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363590) in GitLab 15.2. | | `environment_protected` | Job specifies an environment | `true` if specified environment is protected, `false` otherwise. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294440) in GitLab 13.9. | | `environment` | Job specifies an environment | Environment the job specifies. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294440) in GitLab 13.9. | diff --git a/doc/development/documentation/contribute.md b/doc/development/documentation/contribute.md index 59621aaaad1..8b08743c6e9 100644 --- a/doc/development/documentation/contribute.md +++ b/doc/development/documentation/contribute.md @@ -6,13 +6,42 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Contribute to the GitLab documentation -Everyone is welcome to update the GitLab documentation. +Everyone is welcome to update the GitLab documentation! -If you are looking for something to work on, you can review the list of -[open issues](https://about.gitlab.com/handbook/product/ux/technical-writing/#community-contribution-opportunities) -or work to fix [Vale](testing.md#vale) suggestions. +## Work without an issue -You don't need an issue to update the documentation, however. +You don't need an issue to update the documentation. + +On [https://docs.gitlab.com](https://docs.gitlab.com), at the bottom of any page, +you can select **View page source** or **Edit in Web IDE** and [get started with a merge request](#open-your-merge-request). + +You can alternately: + +- Choose a page [in the `/doc` directory](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc) + and edit it from there. +- Try installing and running the [Vale linting tool](testing.md#vale) + and fixing the resulting issues. + +When you're developing code, the workflow for updating docs is slightly different. +For details, see the [merge request workflow](../contributing/merge_request_workflow.md). + +## Search available issues + +If you're looking for an open issue, you can +[review the list of documentation issues curated specifically for new contributors](https://gitlab.com/gitlab-org/gitlab/-/issues/?sort=created_date&state=opened&label_name%5B%5D=documentation&label_name%5B%5D=docs-only&label_name%5B%5D=Seeking%20community%20contributions&first_page_size=20). + +When you find an issue you'd like to work on: + +- If the issue is already assigned to someone, pick a different one. +- If the issue is unassigned, add a comment and ask to work on the issue. For a Hackathon, use `@docs-hackathon`. Otherwise, use `@gl-docsteam`. For example: + + ```plaintext + @docs-hackathon I would like to work on this issue + ``` + +- Do not ask for more than three issues at a time. + +## Open your merge request When you are ready to update the documentation: diff --git a/doc/development/fe_guide/content_editor.md b/doc/development/fe_guide/content_editor.md index 6d13f419430..5c7fe68fec5 100644 --- a/doc/development/fe_guide/content_editor.md +++ b/doc/development/fe_guide/content_editor.md @@ -64,7 +64,7 @@ Instead, you should obtain an instance of the `ContentEditor` class by listening ```html