diff options
34 files changed, 225 insertions, 101 deletions
@@ -246,7 +246,6 @@ gem 'acts-as-taggable-on', '~> 10.0' # rubocop:todo Gemfile/MissingFeatureCatego # Background jobs gem 'sidekiq', '~> 6.5.10' # rubocop:todo Gemfile/MissingFeatureCategory gem 'sidekiq-cron', '~> 1.8.0' # rubocop:todo Gemfile/MissingFeatureCategory -gem 'redis-namespace', '~> 1.9.0' # rubocop:todo Gemfile/MissingFeatureCategory gem 'gitlab-sidekiq-fetcher', path: 'vendor/gems/sidekiq-reliable-fetch', require: 'sidekiq-reliable-fetch' # rubocop:todo Gemfile/MissingFeatureCategory # Cron Parser diff --git a/Gemfile.checksum b/Gemfile.checksum index 85e476f88f1..0f0a4fde96c 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -507,7 +507,6 @@ {"name":"redcarpet","version":"3.6.0","platform":"ruby","checksum":"8ad1889c0355ff4c47174af14edd06d62f45a326da1da6e8a121d59bdcd2e9e9"}, {"name":"redis","version":"4.8.0","platform":"ruby","checksum":"2000cf5014669c9dc821704b6d322a35a9a33852a95208911d9175d63b448a44"}, {"name":"redis-actionpack","version":"5.3.0","platform":"ruby","checksum":"3fb1ad0a8fd9d26a289c9399bb609dcaef38bf37711e6f677a53ca728fc19140"}, -{"name":"redis-namespace","version":"1.9.0","platform":"ruby","checksum":"0923961f38cf15b86cb57d92507e0a3b32480729eb5033249f5de8b12e0d8612"}, {"name":"redis-rack","version":"2.1.4","platform":"ruby","checksum":"0872eecb303e483c3863d6bd0d47323d230640d41c1a4ac4a2c7596ec0b1774c"}, {"name":"redis-store","version":"1.9.1","platform":"ruby","checksum":"7b4c7438d46f7b7ce8f67fc0eda3a04fc67d32d28cf606cc98a5df4d2b77071d"}, {"name":"regexp_parser","version":"2.6.0","platform":"ruby","checksum":"f163ba463a45ca2f2730e0902f2475bb0eefcd536dfc2f900a86d1e5a7d7a556"}, diff --git a/Gemfile.lock b/Gemfile.lock index 601cfd70894..8bac7b3a18f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1316,8 +1316,6 @@ GEM actionpack (>= 5, < 8) redis-rack (>= 2.1.0, < 3) redis-store (>= 1.1.0, < 2) - redis-namespace (1.9.0) - redis (>= 4) redis-rack (2.1.4) rack (>= 2.0.8, < 3) redis-store (>= 1.2, < 2) @@ -1971,7 +1969,6 @@ DEPENDENCIES recaptcha (~> 5.12) redis (~> 4.8.0) redis-actionpack (~> 5.3.0) - redis-namespace (~> 1.9.0) request_store (~> 1.5.1) responders (~> 3.0) retriable (~> 3.1.2) diff --git a/app/assets/javascripts/ci/runner/components/runner_created_at.vue b/app/assets/javascripts/ci/runner/components/runner_created_at.vue index 5594f4ab486..410142a0eb5 100644 --- a/app/assets/javascripts/ci/runner/components/runner_created_at.vue +++ b/app/assets/javascripts/ci/runner/components/runner_created_at.vue @@ -58,7 +58,7 @@ export default { </template> <template #user> <gl-link - class="js-user-link gl-reset-color gl-reset-font-size gl-font-weight-bold" + class="js-user-link gl-reset-color gl-font-weight-bold" :href="createdBy.webUrl" :data-user-id="createdById" :data-username="createdBy.username" diff --git a/app/assets/javascripts/observability/client.js b/app/assets/javascripts/observability/client.js index 2f25184e9d6..884aa841b68 100644 --- a/app/assets/javascripts/observability/client.js +++ b/app/assets/javascripts/observability/client.js @@ -1,7 +1,9 @@ import * as Sentry from '~/sentry/sentry_browser_wrapper'; import axios from '~/lib/utils/axios_utils'; +import { logError } from '~/lib/logger'; function reportErrorAndThrow(e) { + logError(e); Sentry.captureException(e); throw e; } diff --git a/app/assets/javascripts/observability/components/observability_container.vue b/app/assets/javascripts/observability/components/observability_container.vue index 0a9dec11430..33d05b01556 100644 --- a/app/assets/javascripts/observability/components/observability_container.vue +++ b/app/assets/javascripts/observability/components/observability_container.vue @@ -1,4 +1,6 @@ <script> +import * as Sentry from '~/sentry/sentry_browser_wrapper'; +import { logError } from '~/lib/logger'; import { buildClient } from '../client'; import ObservabilityLoader from './loader/index.vue'; import { CONTENT_STATE } from './loader/constants'; @@ -72,8 +74,9 @@ export default { this.$emit('observability-client-ready', this.observabilityClient); this.loaderContentState = CONTENT_STATE.LOADED; } else if (status === 'error') { - // eslint-disable-next-line @gitlab/require-i18n-strings,no-console - console.error('GOB auth failed with error:', message, statusCode); + const error = new Error(`GOB auth failed with error: ${message} - status: ${statusCode}`); + Sentry.captureException(error); + logError(error); this.loaderContentState = CONTENT_STATE.ERROR; } this.authCompleted = true; diff --git a/app/assets/javascripts/projects/default_project_templates.js b/app/assets/javascripts/projects/default_project_templates.js index 5bbc881952f..e3599c87616 100644 --- a/app/assets/javascripts/projects/default_project_templates.js +++ b/app/assets/javascripts/projects/default_project_templates.js @@ -121,4 +121,8 @@ export default { text: s__('ProjectTemplates|Laravel Framework'), icon: '.template-option .icon-laravel', }, + astro_tailwind: { + text: s__('ProjectTemplates|Astro Tailwind'), + icon: '.template-option .icon-gitlab_logo', + }, }; diff --git a/app/assets/javascripts/vue_shared/components/notes/system_note.vue b/app/assets/javascripts/vue_shared/components/notes/system_note.vue index abebdb84c17..6a5884e4857 100644 --- a/app/assets/javascripts/vue_shared/components/notes/system_note.vue +++ b/app/assets/javascripts/vue_shared/components/notes/system_note.vue @@ -143,7 +143,7 @@ export default { <gl-icon v-if="isAllowedIcon" :name="note.system_note_icon_name" - size="12" + :size="12" data-testid="timeline-icon" /> </div> diff --git a/app/models/ci/catalog/listing.rb b/app/models/ci/catalog/listing.rb index a6f0caa7a40..51bd85016a5 100644 --- a/app/models/ci/catalog/listing.rb +++ b/app/models/ci/catalog/listing.rb @@ -14,8 +14,9 @@ module Ci end def resources(namespace: nil, sort: nil, search: nil) - relation = all_resources(search) + relation = all_resources relation = by_namespace(relation, namespace) + relation = by_search(relation, search) case sort.to_s when 'name_desc' then relation.order_by_name_desc @@ -32,9 +33,9 @@ module Ci attr_reader :current_user - def all_resources(search) + def all_resources Ci::Catalog::Resource.joins(:project).includes(:project) - .merge(find_projects(search)) + .merge(Project.public_or_visible_to_user(current_user)) end def by_namespace(relation, namespace) @@ -44,13 +45,11 @@ module Ci relation.merge(Project.in_namespace(namespace.self_and_descendant_ids)) end - def find_projects(search) - finder_params = { - minimum_search_length: MIN_SEARCH_LENGTH, - search: search - } + def by_search(relation, search) + return relation unless search + return relation.none if search.length < MIN_SEARCH_LENGTH - ProjectsFinder.new(params: finder_params, current_user: current_user).execute + relation.search(search) end end end diff --git a/app/models/ci/catalog/resource.rb b/app/models/ci/catalog/resource.rb index 38841cc309d..e3076e85d10 100644 --- a/app/models/ci/catalog/resource.rb +++ b/app/models/ci/catalog/resource.rb @@ -8,6 +8,8 @@ module Ci # dependency on the Project model and its need to join with that table # in order to generate the CI/CD catalog. class Resource < ::ApplicationRecord + include Gitlab::SQL::Pattern + self.table_name = 'catalog_resources' belongs_to :project @@ -15,6 +17,8 @@ module Ci has_many :versions, class_name: 'Ci::Catalog::Resources::Version', inverse_of: :catalog_resource scope :for_projects, ->(project_ids) { where(project_id: project_ids) } + scope :search, ->(query) { fuzzy_search(query, [:name, :description], use_minimum_char_limit: false) } + scope :order_by_created_at_desc, -> { reorder(created_at: :desc) } scope :order_by_created_at_asc, -> { reorder(created_at: :asc) } scope :order_by_name_desc, -> { reorder(arel_table[:name].desc.nulls_last) } diff --git a/app/services/releases/base_service.rb b/app/services/releases/base_service.rb index 5d6cb372653..088776b896c 100644 --- a/app/services/releases/base_service.rb +++ b/app/services/releases/base_service.rb @@ -111,6 +111,10 @@ module Releases # overridden in EE def project_group_id; end + + def audit(release, action:) + # overridden in EE + end end end diff --git a/app/services/releases/create_service.rb b/app/services/releases/create_service.rb index 95e0861a37a..034cb66c8b9 100644 --- a/app/services/releases/create_service.rb +++ b/app/services/releases/create_service.rb @@ -64,6 +64,8 @@ module Releases create_evidence!(release, evidence_pipeline) + audit(release, action: :created) + success(tag: tag, release: release) rescue StandardError => e error(e.message, 400) diff --git a/app/services/releases/destroy_service.rb b/app/services/releases/destroy_service.rb index 78613c05ff1..1e8338651a8 100644 --- a/app/services/releases/destroy_service.rb +++ b/app/services/releases/destroy_service.rb @@ -11,6 +11,8 @@ module Releases execute_hooks(release, 'delete') + audit(release, action: :deleted) + success(tag: existing_tag, release: release) else error(release.errors.messages || '400 Bad request', 400) diff --git a/app/services/releases/update_service.rb b/app/services/releases/update_service.rb index c11d9468814..13ece1c10c8 100644 --- a/app/services/releases/update_service.rb +++ b/app/services/releases/update_service.rb @@ -19,6 +19,8 @@ module Releases ApplicationRecord.transaction do if release.update(params) execute_hooks(release, 'update') + audit(release, action: :updated) + audit(release, action: :milestones_updated) if milestones_updated?(previous_milestones) success(tag: existing_tag, release: release, milestones_updated: milestones_updated?(previous_milestones)) else error(release.errors.messages || '400 Bad request', 400) diff --git a/config/feature_flags/development/activity_filter_has_remediations.yml b/config/feature_flags/development/activity_filter_has_remediations.yml new file mode 100644 index 00000000000..7a0b5f958f3 --- /dev/null +++ b/config/feature_flags/development/activity_filter_has_remediations.yml @@ -0,0 +1,8 @@ +--- +name: activity_filter_has_remediations +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135009 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/429262 +milestone: '16.6' +type: development +group: group::threat insights +default_enabled: false diff --git a/db/migrate/20231024173744_add_path_to_catalog_resource_components.rb b/db/migrate/20231024173744_add_path_to_catalog_resource_components.rb new file mode 100644 index 00000000000..2473856faf1 --- /dev/null +++ b/db/migrate/20231024173744_add_path_to_catalog_resource_components.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class AddPathToCatalogResourceComponents < Gitlab::Database::Migration[2.2] + milestone '16.6' + disable_ddl_transaction! + + def up + with_lock_retries do + add_column :catalog_resource_components, :path, :text, if_not_exists: true + end + + add_text_limit :catalog_resource_components, :path, 255 + end + + def down + with_lock_retries do + remove_column :catalog_resource_components, :path, :text, if_exists: true + end + end +end diff --git a/db/post_migrate/20231025031337_cleanup_ci_pipeline_messages_pipeline_id_bigint.rb b/db/post_migrate/20231025031337_cleanup_ci_pipeline_messages_pipeline_id_bigint.rb new file mode 100644 index 00000000000..b9e44f8f2d0 --- /dev/null +++ b/db/post_migrate/20231025031337_cleanup_ci_pipeline_messages_pipeline_id_bigint.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class CleanupCiPipelineMessagesPipelineIdBigint < Gitlab::Database::Migration[2.1] + disable_ddl_transaction! + + TABLE = :ci_pipeline_messages + COLUMNS = [:pipeline_id] + + def up + with_lock_retries(raise_on_exhaustion: true) do + lock_tables(:ci_pipelines, TABLE) + cleanup_conversion_of_integer_to_bigint(TABLE, COLUMNS) # rubocop:disable Migration/WithLockRetriesDisallowedMethod + end + end + + def down + restore_conversion_of_integer_to_bigint(TABLE, COLUMNS) + + add_concurrent_index( + TABLE, :pipeline_id_convert_to_bigint, + name: :index_ci_pipeline_messages_on_pipeline_id_convert_to_bigint + ) + add_concurrent_foreign_key( + TABLE, :ci_pipelines, + column: :pipeline_id_convert_to_bigint, + on_delete: :cascade, validate: true, reverse_lock_order: true + ) + end +end diff --git a/db/post_migrate/20231025031539_swap_columns_for_ci_stages_pipeline_id_bigint_for_self_host.rb b/db/post_migrate/20231025031539_swap_columns_for_ci_stages_pipeline_id_bigint_for_self_host.rb new file mode 100644 index 00000000000..c28f49899b6 --- /dev/null +++ b/db/post_migrate/20231025031539_swap_columns_for_ci_stages_pipeline_id_bigint_for_self_host.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +class SwapColumnsForCiStagesPipelineIdBigintForSelfHost < Gitlab::Database::Migration[2.2] + include Gitlab::Database::MigrationHelpers::Swapping + + milestone '16.6' + disable_ddl_transaction! + + TABLE_NAME = :ci_stages + TRIGGER_FUNCTION_NAME = :trigger_07bc3c48f407 + COLUMN_NAME = :pipeline_id + BIGINT_COLUMN_NAME = :pipeline_id_convert_to_bigint + FK_NAME = :fk_fb57e6cc56 + BIGINT_FK_NAME = :fk_c5ddde695f + INDEX_NAMES = %i[ + index_ci_stages_on_pipeline_id + index_ci_stages_on_pipeline_id_and_id + index_ci_stages_on_pipeline_id_and_name + index_ci_stages_on_pipeline_id_and_position + ] + BIGINT_INDEX_NAMES = %i[ + index_ci_stages_on_pipeline_id_convert_to_bigint + index_ci_stages_on_pipeline_id_convert_to_bigint_and_id + index_ci_stages_on_pipeline_id_convert_to_bigint_and_name + index_ci_stages_on_pipeline_id_convert_to_bigint_and_position + ] + + def up + return if column_type_of?(:bigint) + + swap + end + + def down + return if column_type_of?(:integer) + + swap + end + + private + + def column_type_of?(type) + column_for(TABLE_NAME, COLUMN_NAME).sql_type.to_s == type.to_s + end + + def swap + with_lock_retries(raise_on_exhaustion: true) do + # Lock the tables involved. + lock_tables(:ci_pipelines, :ci_stages) + + # Rename the columns to swap names + swap_columns(TABLE_NAME, COLUMN_NAME, BIGINT_COLUMN_NAME) + + # Reset the trigger function + reset_trigger_function(TRIGGER_FUNCTION_NAME) + + # Swap fkey constraint + swap_foreign_keys(TABLE_NAME, FK_NAME, BIGINT_FK_NAME) + + # Swap index + INDEX_NAMES.each_with_index do |index_name, i| + swap_indexes(TABLE_NAME, index_name, BIGINT_INDEX_NAMES[i]) + end + end + end +end diff --git a/db/schema_migrations/20231024173744 b/db/schema_migrations/20231024173744 new file mode 100644 index 00000000000..b262f2a2ebb --- /dev/null +++ b/db/schema_migrations/20231024173744 @@ -0,0 +1 @@ +fd51e236973eaf1d4a2719eaa34dbd7955c2d73e37adf244472c8c69fc486fdf
\ No newline at end of file diff --git a/db/schema_migrations/20231025031337 b/db/schema_migrations/20231025031337 new file mode 100644 index 00000000000..8d28d710397 --- /dev/null +++ b/db/schema_migrations/20231025031337 @@ -0,0 +1 @@ +7dc72ca807126bb992c22879a6d989f282e442ff2c6e15b046e6f3d0f464237f
\ No newline at end of file diff --git a/db/schema_migrations/20231025031539 b/db/schema_migrations/20231025031539 new file mode 100644 index 00000000000..4332cd2b867 --- /dev/null +++ b/db/schema_migrations/20231025031539 @@ -0,0 +1 @@ +4de438a35ae2cbeee4cec03961cf7b5dddfcce2454a1e3ce08985e28b7065a0d
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index a9e416c4c57..255b362c5d0 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -341,15 +341,6 @@ BEGIN END; $$; -CREATE FUNCTION trigger_bfad0e2b9c86() RETURNS trigger - LANGUAGE plpgsql - AS $$ -BEGIN - NEW."pipeline_id_convert_to_bigint" := NEW."pipeline_id"; - RETURN NEW; -END; -$$; - CREATE FUNCTION unset_has_issues_on_vulnerability_reads() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -13196,6 +13187,8 @@ CREATE TABLE catalog_resource_components ( resource_type smallint DEFAULT 1 NOT NULL, inputs jsonb DEFAULT '{}'::jsonb NOT NULL, name text NOT NULL, + path text, + CONSTRAINT check_a76bfd47fe CHECK ((char_length(path) <= 255)), CONSTRAINT check_ddca729980 CHECK ((char_length(name) <= 255)) ); @@ -13919,7 +13912,6 @@ ALTER SEQUENCE ci_pipeline_chat_data_id_seq OWNED BY ci_pipeline_chat_data.id; CREATE TABLE ci_pipeline_messages ( id bigint NOT NULL, severity smallint DEFAULT 0 NOT NULL, - pipeline_id_convert_to_bigint integer DEFAULT 0 NOT NULL, content text NOT NULL, pipeline_id bigint NOT NULL, CONSTRAINT check_58ca2981b2 CHECK ((char_length(content) <= 10000)) @@ -31934,8 +31926,6 @@ CREATE UNIQUE INDEX index_ci_pipeline_chat_data_on_pipeline_id ON ci_pipeline_ch CREATE INDEX index_ci_pipeline_messages_on_pipeline_id ON ci_pipeline_messages USING btree (pipeline_id); -CREATE INDEX index_ci_pipeline_messages_on_pipeline_id_convert_to_bigint ON ci_pipeline_messages USING btree (pipeline_id_convert_to_bigint); - CREATE INDEX index_ci_pipeline_metadata_on_project_id ON ci_pipeline_metadata USING btree (project_id); CREATE UNIQUE INDEX index_ci_pipeline_schedule_variables_on_schedule_id_and_key ON ci_pipeline_schedule_variables USING btree (pipeline_schedule_id, key); @@ -36832,8 +36822,6 @@ CREATE TRIGGER trigger_7f3d66a7d7f5 BEFORE INSERT OR UPDATE ON ci_pipeline_varia CREATE TRIGGER trigger_b2d852e1e2cb BEFORE INSERT OR UPDATE ON ci_pipelines FOR EACH ROW EXECUTE FUNCTION trigger_b2d852e1e2cb(); -CREATE TRIGGER trigger_bfad0e2b9c86 BEFORE INSERT OR UPDATE ON ci_pipeline_messages FOR EACH ROW EXECUTE FUNCTION trigger_bfad0e2b9c86(); - CREATE TRIGGER trigger_delete_project_namespace_on_project_delete AFTER DELETE ON projects FOR EACH ROW WHEN ((old.project_namespace_id IS NOT NULL)) EXECUTE FUNCTION delete_associated_project_namespace(); CREATE TRIGGER trigger_has_external_issue_tracker_on_delete AFTER DELETE ON integrations FOR EACH ROW WHEN ((((old.category)::text = 'issue_tracker'::text) AND (old.active = true) AND (old.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_issue_tracker(); @@ -36924,9 +36912,6 @@ ALTER TABLE ONLY user_interacted_projects ALTER TABLE ONLY merge_request_assignment_events ADD CONSTRAINT fk_08f7602bfd FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE; -ALTER TABLE ONLY ci_pipeline_messages - ADD CONSTRAINT fk_0946fea681 FOREIGN KEY (pipeline_id_convert_to_bigint) REFERENCES ci_pipelines(id) ON DELETE CASCADE; - ALTER TABLE ONLY remote_development_agent_configs ADD CONSTRAINT fk_0a3c0ada56 FOREIGN KEY (cluster_agent_id) REFERENCES cluster_agents(id) ON DELETE CASCADE; diff --git a/doc/policy/experiment-beta-support.md b/doc/policy/experiment-beta-support.md index a87a72d7910..41ffaec3aa4 100644 --- a/doc/policy/experiment-beta-support.md +++ b/doc/policy/experiment-beta-support.md @@ -13,7 +13,7 @@ All other features are considered to be Generally Available (GA). ## Experiment Support is not provided for features listed as "Experimental" or "Alpha" or any similar designation. Issues regarding such features should be opened in the GitLab issue tracker. Teams should release features as GA from the start unless there are strong reasons to release them as Experiment or Beta versions first. -All Experimental features must [initiate Production Readiness Review](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness/#process) and complete the [experiment section in the readiness template](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/.gitlab/issue_templates/production_readiness.md#experiment). +All Experimental features that [meet the review criteria](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness/#criteria-for-starting-a-production-readiness-review) must [initiate Production Readiness Review](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness/#process) and complete the [experiment section in the readiness template](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/.gitlab/issue_templates/production_readiness.md#experiment). Experimental features are: @@ -36,7 +36,7 @@ Experimental features are: ## Beta Commercially-reasonable efforts are made to provide limited support for features designated as "Beta," with the expectation that issues require extra time and assistance from development to troubleshoot. -All Beta features must complete all sections up to and including the [beta section in the readiness template](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/.gitlab/issue_templates/production_readiness.md#beta) by following the [Production Readiness Review process](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness/#process). +All Beta features that [meet the review criteria](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness/#criteria-for-starting-a-production-readiness-review) must complete all sections up to and including the [beta section in the readiness template](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/.gitlab/issue_templates/production_readiness.md#beta) by following the [Production Readiness Review process](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness/#process). Beta features are: @@ -56,7 +56,7 @@ Beta features are: ## Generally Available (GA) -Generally Available features must complete the [Production Readiness Review](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness) and complete all sections up to and including the [GA section in the readiness template](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/.gitlab/issue_templates/production_readiness.md#general-availability). +Generally Available features that [meet the review criteria](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness/#criteria-for-starting-a-production-readiness-review) must complete the [Production Readiness Review](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness) and complete all sections up to and including the [GA section in the readiness template](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/.gitlab/issue_templates/production_readiness.md#general-availability). GA features are: diff --git a/lib/api/releases.rb b/lib/api/releases.rb index 5d056ade3da..83085b5b7e3 100644 --- a/lib/api/releases.rb +++ b/lib/api/releases.rb @@ -270,8 +270,6 @@ module API .execute if result[:status] == :success - log_release_created_audit_event(result[:release]) - present result[:release], with: Entities::Release, current_user: current_user else render_api_error!(result[:message], result[:http_status]) @@ -317,9 +315,6 @@ module API .execute if result[:status] == :success - log_release_updated_audit_event - log_release_milestones_updated_audit_event if result[:milestones_updated] - present result[:release], with: Entities::Release, current_user: current_user else render_api_error!(result[:message], result[:http_status]) @@ -350,8 +345,6 @@ module API .execute if result[:status] == :success - log_release_deleted_audit_event - present result[:release], with: Entities::Release, current_user: current_user else render_api_error!(result[:message], result[:http_status]) @@ -406,22 +399,6 @@ module API Rack::Utils.parse_nested_query(@request.query_string) end - def log_release_created_audit_event(release) - # extended in EE - end - - def log_release_updated_audit_event - # extended in EE - end - - def log_release_deleted_audit_event - # extended in EE - end - - def log_release_milestones_updated_audit_event - # extended in EE - end - def release_cli? request.env['HTTP_USER_AGENT']&.include?(RELEASE_CLI_USER_AGENT) == true end diff --git a/lib/gitlab/project_template.rb b/lib/gitlab/project_template.rb index 23dafc21392..5f2084ce011 100644 --- a/lib/gitlab/project_template.rb +++ b/lib/gitlab/project_template.rb @@ -81,7 +81,8 @@ module Gitlab ProjectTemplate.new('cluster_management', 'GitLab Cluster Management', _('An example project for managing Kubernetes clusters integrated with GitLab'), 'https://gitlab.com/gitlab-org/project-templates/cluster-management'), ProjectTemplate.new('kotlin_native_linux', 'Kotlin Native Linux', _('A basic template for developing Linux programs using Kotlin Native'), 'https://gitlab.com/gitlab-org/project-templates/kotlin-native-linux'), ProjectTemplate.new('typo3_distribution', 'TYPO3 Distribution', _('A template for starting a new TYPO3 project'), 'https://gitlab.com/gitlab-org/project-templates/typo3-distribution', 'illustrations/logos/typo3.svg'), - ProjectTemplate.new('laravel', 'Laravel Framework', _('A basic folder structure of a Laravel application, to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/laravel', 'illustrations/logos/laravel.svg') + ProjectTemplate.new('laravel', 'Laravel Framework', _('A basic folder structure of a Laravel application, to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/laravel', 'illustrations/logos/laravel.svg'), + ProjectTemplate.new('astro_tailwind', 'Astro Tailwind', _('A basic folder structure of Astro Starter Kit, to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/astro-tailwind') ] end # rubocop:enable Metrics/AbcSize diff --git a/lib/gitlab/redis/multi_store.rb b/lib/gitlab/redis/multi_store.rb index bbe5a8add4b..95d27cdb500 100644 --- a/lib/gitlab/redis/multi_store.rb +++ b/lib/gitlab/redis/multi_store.rb @@ -380,7 +380,7 @@ module Gitlab end def redis_store?(store) - store.is_a?(::Redis) || store.is_a?(::Redis::Namespace) + store.is_a?(::Redis) end def validate_stores! diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b885b883d81..5c82f344e3c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1765,6 +1765,9 @@ msgstr "" msgid "A Work Item can be a parent or a child, but not both." msgstr "" +msgid "A basic folder structure of Astro Starter Kit, to help you get started." +msgstr "" + msgid "A basic folder structure of a Laravel application, to help you get started." msgstr "" @@ -37845,6 +37848,9 @@ msgstr "" msgid "ProjectTemplates|Android" msgstr "" +msgid "ProjectTemplates|Astro Tailwind" +msgstr "" + msgid "ProjectTemplates|GitLab Cluster Management" msgstr "" @@ -43462,6 +43468,12 @@ msgstr "" msgid "SecurityReports|Investigate this vulnerability by creating an issue" msgstr "" +msgid "SecurityReports|Is available" +msgstr "" + +msgid "SecurityReports|Is not available" +msgstr "" + msgid "SecurityReports|Issue" msgstr "" @@ -43578,6 +43590,9 @@ msgid_plural "SecurityReports|Show %d items" msgstr[0] "" msgstr[1] "" +msgid "SecurityReports|Solution available" +msgstr "" + msgid "SecurityReports|Sometimes a scanner can't determine a finding's severity. Those findings may still be a potential source of risk though. Please review these manually." msgstr "" diff --git a/spec/frontend/observability/client_spec.js b/spec/frontend/observability/client_spec.js index 7da84b18a91..c8c51b261b6 100644 --- a/spec/frontend/observability/client_spec.js +++ b/spec/frontend/observability/client_spec.js @@ -2,9 +2,11 @@ import MockAdapter from 'axios-mock-adapter'; import * as Sentry from '~/sentry/sentry_browser_wrapper'; import { buildClient } from '~/observability/client'; import axios from '~/lib/utils/axios_utils'; +import { logError } from '~/lib/logger'; jest.mock('~/lib/utils/axios_utils'); jest.mock('~/sentry/sentry_browser_wrapper'); +jest.mock('~/lib/logger'); describe('buildClient', () => { let client; @@ -32,6 +34,11 @@ describe('buildClient', () => { axiosMock.restore(); }); + const expectErrorToBeReported = (e) => { + expect(Sentry.captureException).toHaveBeenCalledWith(e); + expect(logError).toHaveBeenCalledWith(e); + }; + describe('buildClient', () => { it('rejects if params are missing', () => { const e = new Error( @@ -89,7 +96,7 @@ describe('buildClient', () => { const e = 'Request failed with status code 500'; await expect(client.isObservabilityEnabled()).rejects.toThrow(e); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + expectErrorToBeReported(new Error(e)); }); it('throws in case of unexpected response', async () => { @@ -97,7 +104,7 @@ describe('buildClient', () => { const e = 'Failed to check provisioning'; await expect(client.isObservabilityEnabled()).rejects.toThrow(e); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + expectErrorToBeReported(new Error(e)); }); }); @@ -120,7 +127,7 @@ describe('buildClient', () => { const e = 'Request failed with status code 401'; await expect(client.enableObservability()).rejects.toThrow(e); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + expectErrorToBeReported(new Error(e)); }); }); @@ -156,14 +163,14 @@ describe('buildClient', () => { axiosMock.onGet(tracingUrl).reply(200, { traces: [] }); await expect(client.fetchTrace('trace-1')).rejects.toThrow(FETCHING_TRACES_ERROR); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(FETCHING_TRACES_ERROR)); + expectErrorToBeReported(new Error(FETCHING_TRACES_ERROR)); }); it('rejects if traces are invalid', async () => { axiosMock.onGet(tracingUrl).reply(200, { traces: 'invalid' }); await expect(client.fetchTraces()).rejects.toThrow(FETCHING_TRACES_ERROR); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(FETCHING_TRACES_ERROR)); + expectErrorToBeReported(new Error(FETCHING_TRACES_ERROR)); }); }); @@ -196,14 +203,14 @@ describe('buildClient', () => { axiosMock.onGet(tracingUrl).reply(200, {}); await expect(client.fetchTraces()).rejects.toThrow(FETCHING_TRACES_ERROR); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(FETCHING_TRACES_ERROR)); + expectErrorToBeReported(new Error(FETCHING_TRACES_ERROR)); }); it('rejects if traces are invalid', async () => { axiosMock.onGet(tracingUrl).reply(200, { traces: 'invalid' }); await expect(client.fetchTraces()).rejects.toThrow(FETCHING_TRACES_ERROR); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(FETCHING_TRACES_ERROR)); + expectErrorToBeReported(new Error(FETCHING_TRACES_ERROR)); }); describe('query filter', () => { @@ -348,7 +355,7 @@ describe('buildClient', () => { const e = 'failed to fetch services. invalid response'; await expect(client.fetchServices()).rejects.toThrow(e); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + expectErrorToBeReported(new Error(e)); }); }); @@ -375,7 +382,7 @@ describe('buildClient', () => { it('rejects if serviceName is missing', async () => { const e = 'fetchOperations() - serviceName is required.'; await expect(client.fetchOperations()).rejects.toThrow(e); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + expectErrorToBeReported(new Error(e)); }); it('rejects if operationUrl does not contain $SERVICE_NAME$', async () => { @@ -387,7 +394,7 @@ describe('buildClient', () => { }); const e = 'fetchOperations() - operationsUrl must contain $SERVICE_NAME$'; await expect(client.fetchOperations(serviceName)).rejects.toThrow(e); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + expectErrorToBeReported(new Error(e)); }); it('rejects if operations are missing', async () => { @@ -395,7 +402,7 @@ describe('buildClient', () => { const e = 'failed to fetch operations. invalid response'; await expect(client.fetchOperations(serviceName)).rejects.toThrow(e); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + expectErrorToBeReported(new Error(e)); }); }); }); diff --git a/spec/frontend/observability/observability_container_spec.js b/spec/frontend/observability/observability_container_spec.js index 16b1c7b254e..1f5194a1bd8 100644 --- a/spec/frontend/observability/observability_container_spec.js +++ b/spec/frontend/observability/observability_container_spec.js @@ -3,10 +3,13 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ObservabilityContainer from '~/observability/components/observability_container.vue'; import ObservabilityLoader from '~/observability/components/loader/index.vue'; import { CONTENT_STATE } from '~/observability/components/loader/constants'; - import { buildClient } from '~/observability/client'; +import * as Sentry from '~/sentry/sentry_browser_wrapper'; +import { logError } from '~/lib/logger'; jest.mock('~/observability/client'); +jest.mock('~/sentry/sentry_browser_wrapper'); +jest.mock('~/lib/logger'); describe('ObservabilityContainer', () => { let wrapper; @@ -49,6 +52,8 @@ describe('ObservabilityContainer', () => { data: { type: 'AUTH_COMPLETION', status, + message: 'test-message', + statusCode: 'test-code', }, origin: origin ?? new URL(OAUTH_URL).origin, }), @@ -130,6 +135,12 @@ describe('ObservabilityContainer', () => { it('does not emit observability-client-ready', () => { expect(wrapper.emitted('observability-client-ready')).toBeUndefined(); }); + + it('reports the error', () => { + const e = new Error('GOB auth failed with error: test-message - status: test-code'); + expect(Sentry.captureException).toHaveBeenCalledWith(e); + expect(logError).toHaveBeenCalledWith(e); + }); }); it('handles oauth message only once', async () => { diff --git a/spec/lib/gitlab/project_template_spec.rb b/spec/lib/gitlab/project_template_spec.rb index 998fff12e94..07cdbf97091 100644 --- a/spec/lib/gitlab/project_template_spec.rb +++ b/spec/lib/gitlab/project_template_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::ProjectTemplate do +RSpec.describe Gitlab::ProjectTemplate, feature_category: :source_code_management do include ProjectTemplateTestHelper describe '.all' do diff --git a/spec/lib/gitlab/redis/multi_store_spec.rb b/spec/lib/gitlab/redis/multi_store_spec.rb index 1745a745ec3..66860e8a443 100644 --- a/spec/lib/gitlab/redis/multi_store_spec.rb +++ b/spec/lib/gitlab/redis/multi_store_spec.rb @@ -56,7 +56,6 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do context 'when primary_store is not a ::Redis instance' do before do allow(primary_store).to receive(:is_a?).with(::Redis).and_return(false) - allow(primary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(false) end it 'fails with exception' do @@ -65,21 +64,9 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do end end - context 'when primary_store is a ::Redis::Namespace instance' do - before do - allow(primary_store).to receive(:is_a?).with(::Redis).and_return(false) - allow(primary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(true) - end - - it 'fails with exception' do - expect { described_class.new(primary_store, secondary_store, instance_name) }.not_to raise_error - end - end - context 'when secondary_store is not a ::Redis instance' do before do allow(secondary_store).to receive(:is_a?).with(::Redis).and_return(false) - allow(secondary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(false) end it 'fails with exception' do @@ -88,17 +75,6 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do end end - context 'when secondary_store is a ::Redis::Namespace instance' do - before do - allow(secondary_store).to receive(:is_a?).with(::Redis).and_return(false) - allow(secondary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(true) - end - - it 'fails with exception' do - expect { described_class.new(primary_store, secondary_store, instance_name) }.not_to raise_error - end - end - # rubocop:disable RSpec/MultipleMemoizedHelpers context 'with READ redis commands' do subject do diff --git a/spec/models/ci/catalog/resource_spec.rb b/spec/models/ci/catalog/resource_spec.rb index cb9152cfd74..9df6c9d663d 100644 --- a/spec/models/ci/catalog/resource_spec.rb +++ b/spec/models/ci/catalog/resource_spec.rb @@ -9,7 +9,7 @@ RSpec.describe Ci::Catalog::Resource, feature_category: :pipeline_composition do let_it_be_with_reload(:project) { create(:project, name: 'A') } let_it_be(:project_2) { build(:project, name: 'Z') } - let_it_be(:project_3) { build(:project, name: 'L') } + let_it_be(:project_3) { build(:project, name: 'L', description: 'Z') } let_it_be_with_reload(:resource) { create(:ci_catalog_resource, project: project, latest_released_at: tomorrow) } let_it_be(:resource_2) { create(:ci_catalog_resource, project: project_2, latest_released_at: today) } let_it_be(:resource_3) { create(:ci_catalog_resource, project: project_3, latest_released_at: nil) } @@ -36,6 +36,14 @@ RSpec.describe Ci::Catalog::Resource, feature_category: :pipeline_composition do end end + describe '.search' do + it 'returns catalog resources whose name or description match the search term' do + resources = described_class.search('Z') + + expect(resources).to contain_exactly(resource_2, resource_3) + end + end + describe '.order_by_created_at_desc' do it 'returns catalog resources sorted by descending created at' do ordered_resources = described_class.order_by_created_at_desc diff --git a/spec/support/helpers/project_template_test_helper.rb b/spec/support/helpers/project_template_test_helper.rb index 35e40faeea7..a02cd491bca 100644 --- a/spec/support/helpers/project_template_test_helper.rb +++ b/spec/support/helpers/project_template_test_helper.rb @@ -10,6 +10,7 @@ module ProjectTemplateTestHelper serverless_framework tencent_serverless_framework jsonnet cluster_management kotlin_native_linux pelican bridgetown typo3_distribution laravel + astro_tailwind ] end end diff --git a/vendor/project_templates/astro_tailwind.tar.gz b/vendor/project_templates/astro_tailwind.tar.gz Binary files differnew file mode 100644 index 00000000000..4724b01d3f6 --- /dev/null +++ b/vendor/project_templates/astro_tailwind.tar.gz |