diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index 473d3b4a41a..0c38acd1032 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -70,12 +70,12 @@ export default { }, computed: { mdTable() { + const header = 'header'; return [ - // False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26 - '| header | header |', // eslint-disable-line @gitlab/require-i18n-strings + `| ${header} | ${header} |`, '| ------ | ------ |', - '| cell | cell |', // eslint-disable-line @gitlab/require-i18n-strings - '| cell | cell |', // eslint-disable-line @gitlab/require-i18n-strings + '| | |', + '| | |', ].join('\n'); }, mdSuggestion() { diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 06abbece57f..7f8e0ebf935 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -41,7 +41,7 @@ class MergeRequest < ApplicationRecord 'Ci::CompareCodequalityReportsService' => ->(project) { true } }.freeze - MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS = 100 + MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS = 200 belongs_to :target_project, class_name: "Project" belongs_to :source_project, class_name: "Project" diff --git a/db/migrate/20220921201347_add_maven_package_requests_forwarding_to_namespace_package_settings.rb b/db/migrate/20220921201347_add_maven_package_requests_forwarding_to_namespace_package_settings.rb new file mode 100644 index 00000000000..8f858eb7960 --- /dev/null +++ b/db/migrate/20220921201347_add_maven_package_requests_forwarding_to_namespace_package_settings.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class AddMavenPackageRequestsForwardingToNamespacePackageSettings < Gitlab::Database::Migration[2.0] + def change + # adds columns to match the format used in + # Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings#add_cascading_namespace_setting + add_column(:namespace_package_settings, + :maven_package_requests_forwarding, + :boolean, + null: true, + default: nil + ) + + add_column(:namespace_package_settings, + :lock_maven_package_requests_forwarding, + :boolean, + default: false, + null: false + ) + + add_column(:application_settings, + :lock_maven_package_requests_forwarding, + :boolean, + default: false, + null: false + ) + end +end diff --git a/db/migrate/20220929171925_add_pypi_package_requests_forwarding_to_namespace_package_settings.rb b/db/migrate/20220929171925_add_pypi_package_requests_forwarding_to_namespace_package_settings.rb new file mode 100644 index 00000000000..e99640d471f --- /dev/null +++ b/db/migrate/20220929171925_add_pypi_package_requests_forwarding_to_namespace_package_settings.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class AddPypiPackageRequestsForwardingToNamespacePackageSettings < Gitlab::Database::Migration[2.0] + def change + # adds columns to match the format used in + # Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings#add_cascading_namespace_setting + add_column(:namespace_package_settings, + :pypi_package_requests_forwarding, + :boolean, + null: true, + default: nil + ) + + add_column(:namespace_package_settings, + :lock_pypi_package_requests_forwarding, + :boolean, + default: false, + null: false + ) + + add_column(:application_settings, + :lock_pypi_package_requests_forwarding, + :boolean, + default: false, + null: false + ) + end +end diff --git a/db/migrate/20220929172356_add_npm_package_requests_forwarding_to_namespace_package_settings.rb b/db/migrate/20220929172356_add_npm_package_requests_forwarding_to_namespace_package_settings.rb new file mode 100644 index 00000000000..61cc2c26ec7 --- /dev/null +++ b/db/migrate/20220929172356_add_npm_package_requests_forwarding_to_namespace_package_settings.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class AddNpmPackageRequestsForwardingToNamespacePackageSettings < Gitlab::Database::Migration[2.0] + def change + # adds columns to match the format used in + # Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings#add_cascading_namespace_setting + add_column(:namespace_package_settings, + :npm_package_requests_forwarding, + :boolean, + null: true, + default: nil + ) + + add_column(:namespace_package_settings, + :lock_npm_package_requests_forwarding, + :boolean, + default: false, + null: false + ) + + add_column(:application_settings, + :lock_npm_package_requests_forwarding, + :boolean, + default: false, + null: false + ) + end +end diff --git a/db/schema_migrations/20220921201347 b/db/schema_migrations/20220921201347 new file mode 100644 index 00000000000..d58f316fd02 --- /dev/null +++ b/db/schema_migrations/20220921201347 @@ -0,0 +1 @@ +f7c4b6a31434a0f6487fef89ba0c60fd38169e901437667bb6ccf60ba1a3bd4d \ No newline at end of file diff --git a/db/schema_migrations/20220929171925 b/db/schema_migrations/20220929171925 new file mode 100644 index 00000000000..b2e471bb32c --- /dev/null +++ b/db/schema_migrations/20220929171925 @@ -0,0 +1 @@ +352e1b200a7e5074c58fdcfd0c9ae9b3535054a0b3d9852caabde635d9a1ad94 \ No newline at end of file diff --git a/db/schema_migrations/20220929172356 b/db/schema_migrations/20220929172356 new file mode 100644 index 00000000000..3200898ddb5 --- /dev/null +++ b/db/schema_migrations/20220929172356 @@ -0,0 +1 @@ +9cdc6169dc4925f43aabb2f4bcf597333a4112135001a5d1a6961853a78c90da \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index cf56e01d569..122ad10e9ae 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -11485,6 +11485,9 @@ CREATE TABLE application_settings ( dashboard_enforcement_limit integer DEFAULT 0 NOT NULL, dashboard_limit_new_namespace_creation_enforcement_date date, can_create_group boolean DEFAULT true NOT NULL, + lock_maven_package_requests_forwarding boolean DEFAULT false NOT NULL, + lock_pypi_package_requests_forwarding boolean DEFAULT false NOT NULL, + lock_npm_package_requests_forwarding boolean DEFAULT false NOT NULL, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), @@ -17868,6 +17871,12 @@ CREATE TABLE namespace_package_settings ( maven_duplicate_exception_regex text DEFAULT ''::text NOT NULL, generic_duplicates_allowed boolean DEFAULT true NOT NULL, generic_duplicate_exception_regex text DEFAULT ''::text NOT NULL, + maven_package_requests_forwarding boolean, + lock_maven_package_requests_forwarding boolean DEFAULT false NOT NULL, + pypi_package_requests_forwarding boolean, + lock_pypi_package_requests_forwarding boolean DEFAULT false NOT NULL, + npm_package_requests_forwarding boolean, + lock_npm_package_requests_forwarding boolean DEFAULT false NOT NULL, CONSTRAINT check_31340211b1 CHECK ((char_length(generic_duplicate_exception_regex) <= 255)), CONSTRAINT check_d63274b2b6 CHECK ((char_length(maven_duplicate_exception_regex) <= 255)) ); diff --git a/qa/qa/tools/test_resources_handler.rb b/qa/qa/tools/test_resources_handler.rb index 60c6dbfc16c..068fe37a37b 100644 --- a/qa/qa/tools/test_resources_handler.rb +++ b/qa/qa/tools/test_resources_handler.rb @@ -25,13 +25,17 @@ module QA module Tools class TestResourcesHandler include Support::API + include Ci::Helpers - IGNORED_RESOURCES = [ - 'QA::Resource::CiVariable', - 'QA::Resource::Repository::Commit', - 'QA::EE::Resource::GroupIteration', - 'QA::EE::Resource::Settings::Elasticsearch', - 'QA::EE::Resource::VulnerabilityItem' + IGNORED_RESOURCES = %w[ + QA::Resource::CiVariable + QA::Resource::Repository::Commit + QA::Resource::Design + QA::EE::Resource::GroupIteration + QA::EE::Resource::Settings::Elasticsearch + QA::EE::Resource::VulnerabilityItem + QA::EE::Resource::ScanResultPolicyProject + QA::EE::Resource::ScanResultPolicyCommit ].freeze PROJECT = 'gitlab-qa-resources' @@ -44,10 +48,19 @@ module QA def run_delete failures = files.flat_map do |file| resources = read_file(file) - next if resources.nil? + if resources.nil? + logger.info("#{file} is empty, next...") + next + end filtered_resources = filter_resources(resources) + if filtered_resources.nil? + logger.info("No resources left to delete after filtering!") + next + end + delete_resources(filtered_resources) + delete_groups_permanently(filtered_resources['QA::Resource::Group']) end return puts "\nDone" if failures.empty? @@ -62,17 +75,15 @@ module QA # E.g: staging/failed-test-resources-.json def upload(ci_project_name) if files.empty? - puts "\nNothing to upload!" - exit 0 + logger.info("\nNothing to upload!") + return end files.each do |file| file_name = "#{ci_project_name}/#{file.split('/').last}" - Runtime::Logger.info("Uploading #{file_name}...") + logger.info("Uploading #{file_name}...") gcs_storage.put_object(BUCKET, file_name, File.read(file)) end - - puts "\nDone" end # Download files from GCS bucket by environment name @@ -85,40 +96,38 @@ module QA end if files_list.blank? - puts "\nNothing to download!" - exit 0 + logger.info("\nNothing to download!") + return end FileUtils.mkdir_p('tmp/') files_list.each do |file_name| local_path = "tmp/#{file_name.split('/').last}" - Runtime::Logger.info("Downloading #{file_name} to #{local_path}") + logger.info("Downloading #{file_name} to #{local_path}") file = gcs_storage.get_object(BUCKET, file_name) File.write(local_path, file[:body]) - Runtime::Logger.info("Deleting #{file_name} from bucket") + logger.info("Deleting #{file_name} from bucket") gcs_storage.delete_object(BUCKET, file_name) end - - puts "\nDone" end private def files - Runtime::Logger.info('Gathering JSON files...') + logger.info('Gathering JSON files...') files = Dir.glob(@file_pattern) if files.empty? - puts "There is no file with this pattern #{@file_pattern}" + logger.info("There is no file with this pattern #{@file_pattern}") exit 0 end files.reject! { |file| File.zero?(file) } if files.empty? - puts "\nAll files were empty and rejected, nothing more to do!" + logger.info("\nAll files were empty and rejected, nothing more to do!") exit 0 end @@ -126,14 +135,15 @@ module QA end def read_file(file) + logger.info("Reading and processing #{file}...") JSON.parse(File.read(file)) rescue JSON::ParserError - Runtime::Logger.error("Failed to read #{file} - Invalid format") + logger.error("Failed to read #{file} - Invalid format") nil end def filter_resources(resources) - Runtime::Logger.info('Filtering resources - Only keep deletable resources...') + logger.info('Filtering resources - Only keep deletable resources...') transformed_values = resources.transform_values! do |v| v.reject do |attributes| @@ -147,28 +157,55 @@ module QA end def delete_resources(resources) - if resources.nil? - puts "\nNo resources left to delete after filtering!" - exit 0 - end - resources.each_with_object([]) do |(key, value), failures| value.each do |resource| - next if resource_not_found?(resource['api_path']) - resource_info = resource['info'] ? "#{key} - #{resource['info']}" : "#{key} at #{resource['api_path']}" + logger.info("Processing #{resource_info}...") + + if resource_not_found?(resource['api_path']) + logger.info("#{resource['api_path']} returns 404, next...") + next + end + delete_response = delete(Runtime::API::Request.new(api_client, resource['api_path']).url) if delete_response.code == 202 || delete_response.code == 204 - Runtime::Logger.info("Deleting #{resource_info}... SUCCESS") + if key == 'QA::Resource::Group' && !resource_not_found?(resource['api_path']) + logger.info("Successfully marked #{resource_info} for deletion...") + else + logger.info("Deleting #{resource_info}... \e[32mSUCCESS\e[0m") + end else - Runtime::Logger.info("Deleting #{resource_info}... FAILED - #{delete_response}") - failures << resource_info + logger.info("Deleting #{resource_info}... \e[31mFAILED - #{delete_response}\e[0m") + # We might try to delete some groups already marked for deletion, it's fine to ignore these failures + failures << resource_info unless key == 'QA::Resource::Group' end end end end + def delete_groups_permanently(groups) + groups.each_with_object([]) do |group, failures| + logger.info("Processing QA::Resource::Group #{group['info']}...") + + if resource_not_found?(group['api_path']) + logger.info("#{group['api_path']} returns 404, next...") + next + end + + permanent_delete_path = "#{group['api_path']}?permanently_remove=true"\ + "&full_path=#{group['info'].split("'").last}" + response = delete(Runtime::API::Request.new(api_client, permanent_delete_path).url) + + if response.code == 202 + logger.info("Permanently deleting group #{group['info']}... \e[32mSUCCESS\e[0m") + else + logger.info("Permanently deleting group #{group['info']}... \e[31mFAILED - #{response}\e[0m") + failures << "QA::Resource::Group #{group['info']}" + end + end + end + def resource_not_found?(api_path) # if api path contains param "?hard_delete=", remove it get(Runtime::API::Request.new(api_client, api_path.split('?').first).url).code.eql? 404 diff --git a/spec/features/projects/show/user_sees_collaboration_links_spec.rb b/spec/features/projects/show/user_sees_collaboration_links_spec.rb index 1440db141a6..c63427e56e6 100644 --- a/spec/features/projects/show/user_sees_collaboration_links_spec.rb +++ b/spec/features/projects/show/user_sees_collaboration_links_spec.rb @@ -5,8 +5,8 @@ require 'spec_helper' RSpec.describe 'Projects > Show > Collaboration links', :js do using RSpec::Parameterized::TableSyntax - let(:project) { create(:project, :repository, :public) } - let(:user) { create(:user) } + let_it_be(:project) { create(:project, :repository, :public) } + let_it_be(:user) { create(:user) } before do sign_in(user) @@ -17,7 +17,7 @@ RSpec.describe 'Projects > Show > Collaboration links', :js do end context 'with developer user' do - before do + before_all do project.add_developer(user) end diff --git a/spec/frontend/vue_shared/components/markdown/header_spec.js b/spec/frontend/vue_shared/components/markdown/header_spec.js index afeaa5ec850..ed417097e1e 100644 --- a/spec/frontend/vue_shared/components/markdown/header_spec.js +++ b/spec/frontend/vue_shared/components/markdown/header_spec.js @@ -142,7 +142,7 @@ describe('Markdown field header component', () => { const tableButton = findToolbarButtonByProp('icon', 'table'); expect(tableButton.props('tag')).toEqual( - '| header | header |\n| ------ | ------ |\n| cell | cell |\n| cell | cell |', + '| header | header |\n| ------ | ------ |\n| | |\n| | |', ); }); diff --git a/vendor/gems/microsoft_graph_mailer/README.md b/vendor/gems/microsoft_graph_mailer/README.md index dd9dfecfc56..c87748ffdf9 100644 --- a/vendor/gems/microsoft_graph_mailer/README.md +++ b/vendor/gems/microsoft_graph_mailer/README.md @@ -1,6 +1,6 @@ # microsoft_graph_mailer -This gem allows delivery of emails using [Microsoft Graph API](https://docs.microsoft.com/en-us/graph/api/user-sendmail) with [OAuth 2.0 client credentials flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow). +This gem allows delivery of emails using [Microsoft Graph API](https://learn.microsoft.com/en-us/graph/api/user-sendmail) with [OAuth 2.0 client credentials flow](https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow). ## The reason for this gem @@ -30,7 +30,7 @@ gem install microsoft_graph_mailer To use the Microsoft Graph API to send mails, you will need to create an application in the Azure Active Directory. See the -[Microsoft instructions](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) for more details: +[Microsoft instructions](https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) for more details: 1. Sign in to the [Azure portal](https://portal.azure.com). 1. Search for and select `Azure Active Directory`.