diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-10 03:10:37 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-10 03:10:37 +0300 |
commit | 06d5641a544be4c5605ef2b7dcad43d841386ede (patch) | |
tree | 21856b2215a85a171977f9f9e1e4ded12a6ba4af | |
parent | 2051d3c9cece72167a237002c309c720924c88cf (diff) |
Add latest changes from gitlab-org/gitlab@master
42 files changed, 577 insertions, 269 deletions
diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb index add6e1eaf6f..6fc2dfb597b 100644 --- a/app/helpers/preferences_helper.rb +++ b/app/helpers/preferences_helper.rb @@ -4,8 +4,8 @@ module PreferencesHelper def layout_choices [ - ['Fixed', :fixed], - ['Fluid', :fluid] + ['Fixed', :fixed], + ['Fluid', :fluid] ] end @@ -76,7 +76,7 @@ module PreferencesHelper def language_choices options_for_select( - Gitlab::I18n.selectable_locales.map(&:reverse).sort, + selectable_locales_with_translation_level.sort, current_user.preferred_language ) end @@ -107,6 +107,18 @@ module PreferencesHelper def default_first_day_of_week first_day_of_week_choices.rassoc(Gitlab::CurrentSettings.first_day_of_week).first end + + def selectable_locales_with_translation_level + Gitlab::I18n.selectable_locales.map do |code, language| + [ + s_("i18n|%{language} (%{percent_translated}%% translated)") % { + language: language, + percent_translated: Gitlab::I18n.percentage_translated_for(code) + }, + code + ] + end + end end PreferencesHelper.prepend_if_ee('EE::PreferencesHelper') diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb index 2b5390b981f..21f7e410843 100644 --- a/app/models/clusters/applications/prometheus.rb +++ b/app/models/clusters/applications/prometheus.rb @@ -25,18 +25,15 @@ module Clusters key: Settings.attr_encrypted_db_key_base_32, algorithm: 'aes-256-gcm' + default_value_for(:alert_manager_token) { SecureRandom.hex } + after_destroy do - run_after_commit do - disable_prometheus_integration - end + cluster.find_or_build_integration_prometheus.destroy end state_machine :status do after_transition any => [:installed, :externally_installed] do |application| - application.run_after_commit do - Clusters::Applications::ActivateServiceWorker - .perform_async(application.cluster_id, ::PrometheusService.to_param) # rubocop:disable CodeReuse/ServiceClass - end + application.cluster.find_or_build_integration_prometheus.update(enabled: true, alert_manager_token: application.alert_manager_token) end after_transition any => :updating do |application| @@ -103,23 +100,8 @@ module Clusters files.merge('values.yaml': replaced_values) end - def generate_alert_manager_token! - unless alert_manager_token.present? - update!(alert_manager_token: generate_token) - end - end - private - def generate_token - SecureRandom.hex - end - - def disable_prometheus_integration - ::Clusters::Applications::DeactivateServiceWorker - .perform_async(cluster_id, ::PrometheusService.to_param) # rubocop:disable CodeReuse/ServiceClass - end - def install_knative_metrics return [] unless cluster.application_knative_available? diff --git a/app/models/clusters/integrations/prometheus.rb b/app/models/clusters/integrations/prometheus.rb index 1496d8ff1dd..0a01ac5d1ce 100644 --- a/app/models/clusters/integrations/prometheus.rb +++ b/app/models/clusters/integrations/prometheus.rb @@ -4,6 +4,7 @@ module Clusters module Integrations class Prometheus < ApplicationRecord include ::Clusters::Concerns::PrometheusClient + include AfterCommitQueue self.table_name = 'clusters_integration_prometheus' self.primary_key = :cluster_id @@ -13,9 +14,46 @@ module Clusters validates :cluster, presence: true validates :enabled, inclusion: { in: [true, false] } + attr_encrypted :alert_manager_token, + mode: :per_attribute_iv, + key: Settings.attr_encrypted_db_key_base_32, + algorithm: 'aes-256-gcm' + + default_value_for(:alert_manager_token) { SecureRandom.hex } + + after_destroy do + run_after_commit do + deactivate_project_services + end + end + + after_save do + next unless enabled_before_last_save != enabled + + run_after_commit do + if enabled + activate_project_services + else + deactivate_project_services + end + end + end + def available? enabled? end + + private + + def activate_project_services + ::Clusters::Applications::ActivateServiceWorker + .perform_async(cluster_id, ::PrometheusService.to_param) # rubocop:disable CodeReuse/ServiceClass + end + + def deactivate_project_services + ::Clusters::Applications::DeactivateServiceWorker + .perform_async(cluster_id, ::PrometheusService.to_param) # rubocop:disable CodeReuse/ServiceClass + end end end end diff --git a/app/models/user.rb b/app/models/user.rb index 581a1bd893b..c7ad4dcff8a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -433,7 +433,7 @@ class User < ApplicationRecord def preferred_language read_attribute('preferred_language') || - I18n.default_locale.to_s.presence_in(Gitlab::I18n::AVAILABLE_LANGUAGES.keys) || + I18n.default_locale.to_s.presence_in(Gitlab::I18n.available_locales) || 'en' end diff --git a/app/services/clusters/applications/prometheus_config_service.rb b/app/services/clusters/applications/prometheus_config_service.rb index 50c4e26b0d0..d39d63c874f 100644 --- a/app/services/clusters/applications/prometheus_config_service.rb +++ b/app/services/clusters/applications/prometheus_config_service.rb @@ -96,8 +96,6 @@ module Clusters end def alert_manager_token - app.generate_alert_manager_token! - app.alert_manager_token end diff --git a/app/services/projects/prometheus/alerts/notify_service.rb b/app/services/projects/prometheus/alerts/notify_service.rb index 93165a58470..db640a54745 100644 --- a/app/services/projects/prometheus/alerts/notify_service.rb +++ b/app/services/projects/prometheus/alerts/notify_service.rb @@ -63,7 +63,7 @@ module Projects def valid_alert_manager_token?(token, integration) valid_for_manual?(token) || valid_for_alerts_endpoint?(token, integration) || - valid_for_managed?(token) + valid_for_cluster?(token) end def valid_for_manual?(token) @@ -83,18 +83,20 @@ module Projects compare_token(token, integration.token) end - def valid_for_managed?(token) - prometheus_application = available_prometheus_application(project) - return false unless prometheus_application + def valid_for_cluster?(token) + cluster_integration = find_cluster_integration(project) + return false unless cluster_integration + + cluster_integration_token = cluster_integration.alert_manager_token if token - compare_token(token, prometheus_application.alert_manager_token) + compare_token(token, cluster_integration_token) else - prometheus_application.alert_manager_token.nil? + cluster_integration_token.nil? end end - def available_prometheus_application(project) + def find_cluster_integration(project) alert_id = gitlab_alert_id return unless alert_id @@ -105,7 +107,7 @@ module Projects return unless cluster&.enabled? return unless cluster.application_prometheus_available? - cluster.application_prometheus + cluster.application_prometheus || cluster.integration_prometheus end def find_alert(project, metric) diff --git a/app/workers/email_receiver_worker.rb b/app/workers/email_receiver_worker.rb index 618054e8350..37ed1001c9d 100644 --- a/app/workers/email_receiver_worker.rb +++ b/app/workers/email_receiver_worker.rb @@ -9,21 +9,80 @@ class EmailReceiverWorker # rubocop:disable Scalability/IdempotentWorker urgency :high weight 2 + attr_accessor :raw + def perform(raw) - return unless Gitlab::IncomingEmail.enabled? + return unless should_perform? - begin - Gitlab::Email::Receiver.new(raw).execute - rescue StandardError => e - handle_failure(raw, e) - end + @raw = raw + execute_receiver + end + + def should_perform? + Gitlab::IncomingEmail.enabled? end private - def handle_failure(raw, error) - Gitlab::AppLogger.warn("Email can not be processed: #{error}\n\n#{raw}") + def execute_receiver + receiver.execute + log_success + rescue StandardError => e + log_error(e) + handle_failure(e) + end + + def receiver + @receiver ||= Gitlab::Email::Receiver.new(raw) + end + + def logger + Sidekiq.logger + end + + def log_success + logger.info(build_message('Successfully processed message', receiver.mail_metadata)) + end + + def log_error(error) + payload = + case error + # Unparsable e-mails don't have metadata we can use + when Gitlab::Email::EmailUnparsableError, Gitlab::Email::EmptyEmailError + {} + else + mail_metadata + end + + # We don't need the backtrace and more details if the e-mail couldn't be processed + if error.is_a?(Gitlab::Email::ProcessingError) + payload['exception.class'] = error.class.name + else + Gitlab::ExceptionLogFormatter.format!(error, payload) + Gitlab::ErrorTracking.track_exception(error) + end + + logger.error(build_message('Error processing message', payload)) + end + + def build_message(message, params = {}) + { + class: self.class.name, + Labkit::Correlation::CorrelationId::LOG_KEY => Labkit::Correlation::CorrelationId.current_id, + message: message + }.merge(params) + end + + def mail_metadata + receiver.mail_metadata + rescue StandardError => e + # We should never get here as long as we check EmailUnparsableError, but + # let's be defensive in case we did something wrong. + Gitlab::ErrorTracking.track_exception(e) + {} + end + def handle_failure(error) return unless raw.present? can_retry = false diff --git a/app/workers/service_desk_email_receiver_worker.rb b/app/workers/service_desk_email_receiver_worker.rb index 6e1609d6376..e1ef9adc24c 100644 --- a/app/workers/service_desk_email_receiver_worker.rb +++ b/app/workers/service_desk_email_receiver_worker.rb @@ -5,13 +5,11 @@ class ServiceDeskEmailReceiverWorker < EmailReceiverWorker # rubocop:disable Sca sidekiq_options retry: 3 - def perform(raw) - return unless ::Gitlab::ServiceDeskEmail.enabled? + def should_perform? + ::Gitlab::ServiceDeskEmail.enabled? + end - begin - Gitlab::Email::ServiceDeskReceiver.new(raw).execute - rescue StandardError => e - handle_failure(raw, e) - end + def receiver + @receiver ||= Gitlab::Email::ServiceDeskReceiver.new(raw) end end diff --git a/changelogs/unreleased/add-alert-manager-token-to-prometheus-cluster-integration.yml b/changelogs/unreleased/add-alert-manager-token-to-prometheus-cluster-integration.yml new file mode 100644 index 00000000000..d6e6892540b --- /dev/null +++ b/changelogs/unreleased/add-alert-manager-token-to-prometheus-cluster-integration.yml @@ -0,0 +1,5 @@ +--- +title: Keep new prometheus cluster integration in sync with old cluster application +merge_request: 60877 +author: +type: changed diff --git a/changelogs/unreleased/kassio-add-translation-percentage-level-to-ui.yml b/changelogs/unreleased/kassio-add-translation-percentage-level-to-ui.yml new file mode 100644 index 00000000000..545bac66c9b --- /dev/null +++ b/changelogs/unreleased/kassio-add-translation-percentage-level-to-ui.yml @@ -0,0 +1,5 @@ +--- +title: 'i18n: Show translation levels for each language in the UI' +merge_request: 60905 +author: +type: changed diff --git a/changelogs/unreleased/sh-improve-email-receiver-logging.yml b/changelogs/unreleased/sh-improve-email-receiver-logging.yml new file mode 100644 index 00000000000..4394b76be4d --- /dev/null +++ b/changelogs/unreleased/sh-improve-email-receiver-logging.yml @@ -0,0 +1,5 @@ +--- +title: Improve logging in e-mail receiver processing +merge_request: 60692 +author: +type: added diff --git a/db/migrate/20210430034712_add_alert_manager_token_to_clusters_integration_prometheus.rb b/db/migrate/20210430034712_add_alert_manager_token_to_clusters_integration_prometheus.rb new file mode 100644 index 00000000000..48ab860a63b --- /dev/null +++ b/db/migrate/20210430034712_add_alert_manager_token_to_clusters_integration_prometheus.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class AddAlertManagerTokenToClustersIntegrationPrometheus < ActiveRecord::Migration[6.0] + def change + change_table :clusters_integration_prometheus do |t| + t.text :encrypted_alert_manager_token + t.text :encrypted_alert_manager_token_iv + end + end +end diff --git a/db/schema_migrations/20210430034712 b/db/schema_migrations/20210430034712 new file mode 100644 index 00000000000..df9fe0755cf --- /dev/null +++ b/db/schema_migrations/20210430034712 @@ -0,0 +1 @@ +6b7436d7712e31ca116204d37270435ccc059ca75a128750e5c39fdddfa020e3
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 976ac394aae..332682b9eb9 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -11701,7 +11701,9 @@ CREATE TABLE clusters_integration_prometheus ( created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, cluster_id bigint NOT NULL, - enabled boolean DEFAULT false NOT NULL + enabled boolean DEFAULT false NOT NULL, + encrypted_alert_manager_token text, + encrypted_alert_manager_token_iv text ); CREATE TABLE clusters_kubernetes_namespaces ( diff --git a/doc/development/i18n/merging_translations.md b/doc/development/i18n/merging_translations.md index 553820733e7..48474a68d16 100644 --- a/doc/development/i18n/merging_translations.md +++ b/doc/development/i18n/merging_translations.md @@ -78,3 +78,10 @@ recreate it with the following steps: 1. Select the `gitlab-org/gitlab` repository. 1. In `Select Branches for Translation`, select `master`. 1. Ensure the `Service Branch Name` is `master-i18n`. + +## Manually update the translation levels + +There's no automated way to pull the translation levels from CrowdIn, to display +this information in the language selection dropdown. Therefore, the translation +levels are hard-coded in the `TRANSLATION_LEVELS` constant in [`i18n.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/i18n.rb), +and must be regularly updated. diff --git a/doc/user/project/import/bitbucket.md b/doc/user/project/import/bitbucket.md index 6f274dd12a2..e77932c6427 100644 --- a/doc/user/project/import/bitbucket.md +++ b/doc/user/project/import/bitbucket.md @@ -14,26 +14,27 @@ Server (aka Stash). If you are trying to import projects from Bitbucket Server, Import your projects from Bitbucket Cloud to GitLab with minimal effort. -## Overview - -- At its current state, the Bitbucket importer can import: - - the repository description (GitLab 7.7+) - - the Git repository data (GitLab 7.7+) - - the issues (GitLab 7.7+) - - the issue comments (GitLab 8.15+) - - the pull requests (GitLab 8.4+) - - the pull request comments (GitLab 8.15+) - - the milestones (GitLab 8.15+) - - the wiki (GitLab 8.15+) -- References to pull requests and issues are preserved (GitLab 8.7+) -- Repository public access is retained. If a repository is private in Bitbucket - it will be created as private in GitLab as well. +The Bitbucket importer can import: + +- Repository description (GitLab 7.7+) +- Git repository data (GitLab 7.7+) +- Issues (GitLab 7.7+) +- Issue comments (GitLab 8.15+) +- Pull requests (GitLab 8.4+) +- Pull request comments (GitLab 8.15+) +- Milestones (GitLab 8.15+) +- Wiki (GitLab 8.15+) + +When importing: + +- References to pull requests and issues are preserved (GitLab 8.7+). +- Repository public access is retained. If a repository is private in Bitbucket, it's created as + private in GitLab as well. ## Requirements -The [Bitbucket Cloud integration](../../../integration/bitbucket.md) must be first enabled in order to be -able to import your projects from Bitbucket Cloud. Ask your GitLab administrator -to enable this if not already. +To import your projects from Bitbucket Cloud, the [Bitbucket Cloud integration](../../../integration/bitbucket.md) +must be enabled. Ask your GitLab administrator to enable this if it isn't already enabled. ## How it works diff --git a/doc/user/project/import/bitbucket_server.md b/doc/user/project/import/bitbucket_server.md index 9e0d30f4f76..330ed0cb774 100644 --- a/doc/user/project/import/bitbucket_server.md +++ b/doc/user/project/import/bitbucket_server.md @@ -15,31 +15,31 @@ Use the [Bitbucket Cloud importer](bitbucket.md) for that. Import your projects from Bitbucket Server to GitLab with minimal effort. -## Overview +The Bitbucket importer can import: -- In its current state, the Bitbucket importer can import: - - the repository description (GitLab 11.2+) - - the Git repository data (GitLab 11.2+) - - the pull requests (GitLab 11.2+) - - the pull request comments (GitLab 11.2+) -- Repository public access is retained. If a repository is private in Bitbucket - it will be created as private in GitLab as well. +- Repository description (GitLab 11.2+) +- Git repository data (GitLab 11.2+) +- Pull requests (GitLab 11.2+) +- Pull request comments (GitLab 11.2+) + +When importing: + +- Repository public access is retained. If a repository is private in Bitbucket, it's created as + private in GitLab as well. ## Limitations -1. Currently GitLab doesn't allow comments on arbitrary lines of code, so any - Bitbucket comments out of bounds are inserted as comments in the merge - request. -1. Bitbucket Server allows multiple levels of threading. GitLab import - collapses this into one thread and quote part of the original comment. -1. Declined pull requests have unreachable commits, which prevents the GitLab - importer from generating a proper diff. These pull requests show up as - empty changes. -1. Attachments in Markdown are currently not imported. -1. Task lists are not imported. -1. Emoji reactions are not imported -1. Project filtering does not support fuzzy search (only `starts with` or `full - match strings` are currently supported) +- GitLab doesn't allow comments on arbitrary lines of code, so any Bitbucket comments out of bounds + are inserted as comments in the merge request. +- Bitbucket Server allows multiple levels of threading. GitLab import collapses this into one thread + and quote part of the original comment. +- Declined pull requests have unreachable commits, which prevents the GitLab importer from + generating a proper diff. These pull requests show up as empty changes. +- Attachments in Markdown are not imported. +- Task lists are not imported. +- Emoji reactions are not imported. +- Project filtering does not support fuzzy search (only `starts with` or `full match strings` are + supported). ## How it works @@ -104,7 +104,7 @@ To disable it: Feature.disable(:bitbucket_server_user_mapping_by_username) ``` -## Importing your Bitbucket repositories +## Import your Bitbucket repositories 1. Sign in to GitLab and go to your dashboard. 1. Click on **New project**. diff --git a/doc/user/project/import/fogbugz.md b/doc/user/project/import/fogbugz.md index 1371ca57bc9..09505d94a8c 100644 --- a/doc/user/project/import/fogbugz.md +++ b/doc/user/project/import/fogbugz.md @@ -8,12 +8,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Import your project from FogBugz to GitLab It only takes a few simple steps to import your project from FogBugz. -The importer will import all of your cases and comments with original case -numbers and timestamps. You will also have the opportunity to map FogBugz -users to GitLab users. +The importer imports all your cases and comments with original case +numbers and timestamps. You can also map FogBugz users to GitLab users. -1. From your GitLab dashboard click 'New project' -1. Click on the 'FogBugz' button +Follow these steps to import your project from FogBugz: + +1. From your GitLab dashboard, select **New project**. + +1. Select the **FogBugz** button. ![FogBugz](img/fogbugz_import_select_fogbogz.png) @@ -25,11 +27,11 @@ users to GitLab users. ![User Map](img/fogbugz_import_user_map.png) -1. Select the projects you wish to import by clicking the Import buttons +1. Select the projects you wish to import by selecting the **Import** buttons. ![Import Project](img/fogbugz_import_select_project.png) -1. Once the import has finished click the link to take you to the project +1. Once the import finishes, click the link to go to the project dashboard. Follow the directions to push your existing repository. ![Finished](img/fogbugz_import_finished.png) diff --git a/doc/user/project/import/gitea.md b/doc/user/project/import/gitea.md index 5a69a9ff977..255d083be6f 100644 --- a/doc/user/project/import/gitea.md +++ b/doc/user/project/import/gitea.md @@ -9,20 +9,22 @@ info: To determine the technical writer assigned to the Stage/Group associated w Import your projects from Gitea to GitLab with minimal effort. -## Overview - NOTE: This requires Gitea `v1.0.0` or newer. -- At its current state, Gitea importer can import: - - the repository description (GitLab 8.15+) - - the Git repository data (GitLab 8.15+) - - the issues (GitLab 8.15+) - - the pull requests (GitLab 8.15+) - - the milestones (GitLab 8.15+) - - the labels (GitLab 8.15+) -- Repository public access is retained. If a repository is private in Gitea - it will be created as private in GitLab as well. +The Gitea importer can import: + +- Repository description (GitLab 8.15+) +- Git repository data (GitLab 8.15+) +- Issues (GitLab 8.15+) +- Pull requests (GitLab 8.15+) +- Milestones (GitLab 8.15+) +- Labels (GitLab 8.15+) + +When importing: + +- Repository public access is retained. If a repository is private in Gitea it's created as private + in GitLab as well. ## How it works @@ -35,13 +37,13 @@ The importer creates any new namespaces (groups) if they don't exist or in the case the namespace is taken, the repository is imported under the user's namespace that started the import process. -## Importing your Gitea repositories +## Import your Gitea repositories The importer page is visible when you create a new project. ![New project page on GitLab](img/import_projects_from_new_project_page.png) -Click on the **Gitea** link and the import authorization process starts. +Click the **Gitea** link and the import authorization process starts. ![New Gitea project import](img/import_projects_from_gitea_new_import.png) diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md index b5b461b16c1..c8b973b673e 100644 --- a/doc/user/project/import/github.md +++ b/doc/user/project/import/github.md @@ -10,8 +10,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w Using the importer, you can import your GitHub repositories to GitLab.com or to your self-managed GitLab instance. -## Overview - The following aspects of a project are imported: - Repository description (GitLab.com & 7.7+) @@ -37,12 +35,12 @@ The namespace is a user or group in GitLab, such as `gitlab.com/janedoe` or `git This process does not migrate or import any types of groups or organizations from GitHub to GitLab. -### Use cases +## Use cases The steps you take depend on whether you are importing from GitHub.com or GitHub Enterprise, as well as whether you are importing to GitLab.com or self-managed GitLab instance. - If you're importing to GitLab.com, you can alternatively import GitHub repositories - using a [personal access token](#using-a-github-token). We do not recommend + using a [personal access token](#use-a-github-token). We do not recommend this method, as it does not associate all user activity (such as issues and pull requests) with matching GitLab users. - If you're importing to a self-managed GitLab instance, you can alternatively use the @@ -93,7 +91,7 @@ For an overview of the import process, see the video [Migrating from GitHub to G ## Import your GitHub repository into GitLab -### Using the GitHub integration +### Use the GitHub integration Before you begin, ensure that any GitHub users who you want to map to GitLab users have either: @@ -112,9 +110,9 @@ If you are using a self-managed GitLab instance or if you are importing from Git 1. Select the **Import project** tab and then select **GitHub**. 1. Select the first button to **List your GitHub repositories**. You are redirected to a page on [GitHub](https://github.com) to authorize the GitLab application. 1. Click **Authorize GitlabHQ**. You are redirected back to the GitLab Import page and all of your GitHub repositories are listed. -1. Continue on to [selecting which repositories to import](#selecting-which-repositories-to-import). +1. Continue on to [selecting which repositories to import](#select-which-repositories-to-import). -### Using a GitHub token +### Use a GitHub token NOTE: Using a personal access token to import projects is not recommended. If you are a GitLab.com user, @@ -122,7 +120,7 @@ you can use a personal access token to import your project from GitHub, but this associate all user activity (such as issues and pull requests) with matching GitLab users. If you are an administrator of a self-managed GitLab instance or if you are importing from GitHub Enterprise, you cannot use a personal access token. -The [GitHub integration method (above)](#using-the-github-integration) is recommended for all users. +The [GitHub integration method (above)](#use-the-github-integration) is recommended for all users. Read more in the [How it works](#how-it-works) section. If you are not using the GitHub integration, you can still perform an authorization with GitHub to grant GitLab access your repositories: @@ -136,7 +134,7 @@ If you are not using the GitHub integration, you can still perform an authorizat 1. Hit the **List Your GitHub Repositories** button and wait while GitLab reads your repositories' information. Once done, you'll be taken to the importer page to select the repositories to import. -### Selecting which repositories to import +### Select which repositories to import After you have authorized access to your GitHub repositories, you are redirected to the GitHub importer page and your GitHub repositories are listed. @@ -162,7 +160,7 @@ Additionally, you can configure GitLab to send pipeline status updates back GitH If you import your project using [CI/CD for external repository](../../../ci/ci_cd_for_external_repos/index.md), then both of the above are automatically configured. **(PREMIUM)** -## Improving the speed of imports on self-managed instances +## Improve the speed of imports on self-managed instances NOTE: Administrator access to the GitLab server is required. diff --git a/doc/user/project/import/jira.md b/doc/user/project/import/jira.md index 5fb737cf74a..6b8c34fada6 100644 --- a/doc/user/project/import/jira.md +++ b/doc/user/project/import/jira.md @@ -54,13 +54,13 @@ Make sure you have the integration set up before trying to import Jira issues. > New import form [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216145) in GitLab 13.2. -To import Jira issues to a GitLab project, follow the steps below. - NOTE: Importing Jira issues is done as an asynchronous background job, which may result in delays based on import queues load, system load, or other factors. Importing large projects may take several minutes depending on the size of the import. +To import Jira issues to a GitLab project, follow these steps: + 1. On the **{issues}** **Issues** page, click **Import Issues** (**{import}**) **> Import from Jira**. ![Import issues from Jira button](img/jira/import_issues_from_jira_button_v12_10.png) diff --git a/doc/user/project/import/manifest.md b/doc/user/project/import/manifest.md index a116cc83a8e..0c383a8baec 100644 --- a/doc/user/project/import/manifest.md +++ b/doc/user/project/import/manifest.md @@ -49,9 +49,9 @@ As a result, the following projects are created: | `https://gitlab.com/YOUR_GROUP/build/make` | <https://android.googlesource.com/platform/build> | | `https://gitlab.com/YOUR_GROUP/build/blueprint` | <https://android.googlesource.com/platform/build/blueprint> | -## Importing the repositories +## Import the repositories -You can start the import with: +Follow these steps to start the import: 1. From your GitLab dashboard click **New project** 1. Switch to the **Import project** tab diff --git a/doc/user/project/import/phabricator.md b/doc/user/project/import/phabricator.md index 91fd7b8928b..30a63a72cf9 100644 --- a/doc/user/project/import/phabricator.md +++ b/doc/user/project/import/phabricator.md @@ -20,7 +20,7 @@ GitLab allows you to import all tasks from a Phabricator instance into GitLab issues. The import creates a single project with the repository disabled. -Currently, only the following basic fields are imported: +Only the following basic fields are imported: - Title - Description @@ -34,6 +34,6 @@ The assignee and author of a user are deducted from a Task's owner and author: If a user with the same username has access to the namespace of the project being imported into, then the user will be linked. -## Enabling this feature +## Enable this feature Enable Phabricator as an [import source](../../admin_area/settings/visibility_and_access_controls.md#import-sources) in the Admin Area. diff --git a/doc/user/project/import/svn.md b/doc/user/project/import/svn.md index 8be69cdeb79..2a58a52ce2c 100644 --- a/doc/user/project/import/svn.md +++ b/doc/user/project/import/svn.md @@ -11,18 +11,16 @@ Subversion (SVN) is a central version control system (VCS) while Git is a distributed version control system. There are some major differences between the two, for more information consult your favorite search engine. -## Overview - There are two approaches to SVN to Git migration: -1. [Git/SVN Mirror](#smooth-migration-with-a-gitsvn-mirror-using-subgit) which: - - Makes the GitLab repository to mirror the SVN project. - - Git and SVN repositories are kept in sync; you can use either one. - - Smoothens the migration process and allows to manage migration risks. +- [Git/SVN Mirror](#smooth-migration-with-a-gitsvn-mirror-using-subgit) which: + - Makes the GitLab repository to mirror the SVN project. + - Git and SVN repositories are kept in sync; you can use either one. + - Smoothens the migration process and allows to manage migration risks. -1. [Cut over migration](#cut-over-migration-with-svn2git) which: - - Translates and imports the existing data and history from SVN to Git. - - Is a fire and forget approach, good for smaller teams. +- [Cut over migration](#cut-over-migration-with-svn2git) which: + - Translates and imports the existing data and history from SVN to Git. + - Is a fire and forget approach, good for smaller teams. ## Smooth migration with a Git/SVN mirror using SubGit diff --git a/doc/user/project/import/tfvc.md b/doc/user/project/import/tfvc.md index 0d347a16697..ef44989d7f2 100644 --- a/doc/user/project/import/tfvc.md +++ b/doc/user/project/import/tfvc.md @@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w type: concepts --- -# Migrating from TFVC to Git +# Migrate from TFVC to Git Team Foundation Server (TFS), renamed [Azure DevOps Server](https://azure.microsoft.com/en-us/services/devops/server/) in 2019, is a set of tools developed by Microsoft which also includes @@ -48,10 +48,10 @@ Migration options from TFVC to Git depend on your operating system. - If you're migrating on Microsoft Windows: - Use the [`git-tfs`](https://github.com/git-tfs/git-tfs) -tool. - Read the [Migrate TFS to Git](https://github.com/git-tfs/git-tfs/blob/master/doc/usecases/migrate_tfs_to_git.md) guide for details. + - Use the [`git-tfs`](https://github.com/git-tfs/git-tfs) + tool. See [Migrate TFS to Git](https://github.com/git-tfs/git-tfs/blob/master/doc/usecases/migrate_tfs_to_git.md) + for details. - If you're on a Unix-based system: - Follow the procedures described with this [TFVC to Git migration tool](https://github.com/turbo/gtfotfs). + - Follow the procedures described with this [TFVC to Git migration tool](https://github.com/turbo/gtfotfs). diff --git a/lib/gitlab/email/receiver.rb b/lib/gitlab/email/receiver.rb index f5e47b43a9a..71db8ab6067 100644 --- a/lib/gitlab/email/receiver.rb +++ b/lib/gitlab/email/receiver.rb @@ -6,6 +6,8 @@ require_dependency 'gitlab/email/handler' module Gitlab module Email class Receiver + include Gitlab::Utils::StrongMemoize + def initialize(raw) @raw = raw end @@ -13,11 +15,7 @@ module Gitlab def execute raise EmptyEmailError if @raw.blank? - mail = build_mail - - ignore_auto_reply!(mail) - - handler = find_handler(mail) + ignore_auto_reply! raise UnknownIncomingEmail unless handler @@ -26,13 +24,33 @@ module Gitlab end end + def mail_metadata + { + mail_uid: mail.message_id, + from_address: mail.from, + to_address: mail.to, + mail_key: mail_key, + references: Array(mail.references), + delivered_to: delivered_to.map(&:value), + envelope_to: envelope_to.map(&:value), + x_envelope_to: x_envelope_to.map(&:value) + } + end + private - def find_handler(mail) - mail_key = extract_mail_key(mail) + def handler + strong_memoize(:handler) { find_handler } + end + + def find_handler Handler.for(mail, mail_key) end + def mail + strong_memoize(:mail) { build_mail } + end + def build_mail Mail::Message.new(@raw) rescue Encoding::UndefinedConversionError, @@ -40,22 +58,24 @@ module Gitlab raise EmailUnparsableError, e end - def extract_mail_key(mail) - key_from_to_header(mail) || key_from_additional_headers(mail) + def mail_key + strong_memoize(:mail_key) do + key_from_to_header || key_from_additional_headers + end end - def key_from_to_header(mail) + def key_from_to_header mail.to.find do |address| key = Gitlab::IncomingEmail.key_from_address(address) break key if key end end - def key_from_additional_headers(mail) - find_key_from_references(mail) || - find_key_from_delivered_to_header(mail) || - find_key_from_envelope_to_header(mail) || - find_key_from_x_envelope_to_header(mail) + def key_from_additional_headers + find_key_from_references || + find_key_from_delivered_to_header || + find_key_from_envelope_to_header || + find_key_from_x_envelope_to_header end def ensure_references_array(references) @@ -71,41 +91,53 @@ module Gitlab end end - def find_key_from_references(mail) + def find_key_from_references ensure_references_array(mail.references).find do |mail_id| key = Gitlab::IncomingEmail.key_from_fallback_message_id(mail_id) break key if key end end - def find_key_from_delivered_to_header(mail) - Array(mail[:delivered_to]).find do |header| + def delivered_to + Array(mail[:delivered_to]) + end + + def envelope_to + Array(mail[:envelope_to]) + end + + def x_envelope_to + Array(mail[:x_envelope_to]) + end + + def find_key_from_delivered_to_header + delivered_to.find do |header| key = Gitlab::IncomingEmail.key_from_address(header.value) break key if key end end - def find_key_from_envelope_to_header(mail) - Array(mail[:envelope_to]).find do |header| + def find_key_from_envelope_to_header + envelope_to.find do |header| key = Gitlab::IncomingEmail.key_from_address(header.value) break key if key end end - def find_key_from_x_envelope_to_header(mail) - Array(mail[:x_envelope_to]).find do |header| + def find_key_from_x_envelope_to_header + x_envelope_to.find do |header| key = Gitlab::IncomingEmail.key_from_address(header.value) break key if key end end - def ignore_auto_reply!(mail) - if auto_submitted?(mail) || auto_replied?(mail) + def ignore_auto_reply! + if auto_submitted? || auto_replied? raise AutoGeneratedEmailError end end - def auto_submitted?(mail) + def auto_submitted? # Mail::Header#[] is case-insensitive auto_submitted = mail.header['Auto-Submitted']&.value @@ -114,7 +146,7 @@ module Gitlab auto_submitted && auto_submitted != 'no' end - def auto_replied?(mail) + def auto_replied? autoreply = mail.header['X-Autoreply']&.value autoreply && autoreply == 'yes' diff --git a/lib/gitlab/email/service_desk_receiver.rb b/lib/gitlab/email/service_desk_receiver.rb index 1ee5c10097b..133c4ee4b45 100644 --- a/lib/gitlab/email/service_desk_receiver.rb +++ b/lib/gitlab/email/service_desk_receiver.rb @@ -5,14 +5,19 @@ module Gitlab class ServiceDeskReceiver < Receiver private - def find_handler(mail) - key = service_desk_key(mail) - return unless key + def find_handler + return unless service_desk_key - Gitlab::Email::Handler::ServiceDeskHandler.new(mail, nil, service_desk_key: key) + Gitlab::Email::Handler::ServiceDeskHandler.new(mail, nil, service_desk_key: service_desk_key) end - def service_desk_key(mail) + def service_desk_key + strong_memoize(:service_desk_key) do + find_service_desk_key + end + end + + def find_service_desk_key mail.to.find do |address| key = ::Gitlab::ServiceDeskEmail.key_from_address(address) break key if key diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb index 3b19ae3d7ff..a2c1c96815c 100644 --- a/lib/gitlab/i18n.rb +++ b/lib/gitlab/i18n.rb @@ -4,20 +4,6 @@ module Gitlab module I18n extend self - # Languages with less then 2% of available translations will not - # be available in the UI. - # https://gitlab.com/gitlab-org/gitlab/-/issues/221012 - NOT_AVAILABLE_IN_UI = %w[ - fil_PH - pl_PL - nl_NL - id_ID - cs_CZ - bg - eo - gl_ES - ].freeze - AVAILABLE_LANGUAGES = { 'bg' => 'Bulgarian - български', 'cs_CZ' => 'Czech - čeština', @@ -42,9 +28,49 @@ module Gitlab 'zh_HK' => 'Chinese, Traditional (Hong Kong) - 繁體中文 (香港)', 'zh_TW' => 'Chinese, Traditional (Taiwan) - 繁體中文 (台灣)' }.freeze + private_constant :AVAILABLE_LANGUAGES + + # Languages with less then MINIMUM_TRANSLATION_LEVEL% of available translations will not + # be available in the UI. + # https://gitlab.com/gitlab-org/gitlab/-/issues/221012 + MINIMUM_TRANSLATION_LEVEL = 2 + + # Currently monthly updated manually by ~group::import PM. + # https://gitlab.com/gitlab-org/gitlab/-/issues/18923 + TRANSLATION_LEVELS = { + 'bg' => 1, + 'cs_CZ' => 1, + 'de' => 20, + 'en' => 100, + 'eo' => 1, + 'es' => 44, + 'fil_PH' => 1, + 'fr' => 14, + 'gl_ES' => 1, + 'id_ID' => 0, + 'it' => 3, + 'ja' => 49, + 'ko' => 15, + 'nl_NL' => 1, + 'pl_PL' => 1, + 'pt_BR' => 23, + 'ru' => 34, + 'tr_TR' => 18, + 'uk' => 46, + 'zh_CN' => 78, + 'zh_HK' => 3, + 'zh_TW' => 4 + }.freeze + private_constant :TRANSLATION_LEVELS def selectable_locales - AVAILABLE_LANGUAGES.reject { |key, _value| NOT_AVAILABLE_IN_UI.include? key } + AVAILABLE_LANGUAGES.reject do |code, _name| + percentage_translated_for(code) < MINIMUM_TRANSLATION_LEVEL + end + end + + def percentage_translated_for(code) + TRANSLATION_LEVELS.fetch(code, 0) end def available_locales diff --git a/lib/gitlab/prometheus/adapter.rb b/lib/gitlab/prometheus/adapter.rb index 76e65d29c7a..45438d9bf7c 100644 --- a/lib/gitlab/prometheus/adapter.rb +++ b/lib/gitlab/prometheus/adapter.rb @@ -19,13 +19,11 @@ module Gitlab end def cluster_prometheus_adapter - if cluster&.integration_prometheus - return cluster.integration_prometheus - end - application = cluster&.application_prometheus + return application if application&.available? - application if application&.available? + integration = cluster&.integration_prometheus + integration if integration&.available? end private diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 55356dba1b6..557cf5525b6 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -38107,6 +38107,9 @@ msgstr "" msgid "https://your-bitbucket-server" msgstr "" +msgid "i18n|%{language} (%{percent_translated}%% translated)" +msgstr "" + msgid "image diff" msgstr "" diff --git a/spec/deprecation_toolkit_env.rb b/spec/deprecation_toolkit_env.rb index 2359765fedd..57d32b5423c 100644 --- a/spec/deprecation_toolkit_env.rb +++ b/spec/deprecation_toolkit_env.rb @@ -59,6 +59,7 @@ module DeprecationToolkitEnv activesupport-6.0.3.6/lib/active_support/cache.rb activerecord-6.0.3.6/lib/active_record/relation.rb asciidoctor-2.0.12/lib/asciidoctor/extensions.rb + attr_encrypted-3.1.0/lib/attr_encrypted/adapters/active_record.rb ] end diff --git a/spec/features/profiles/user_edit_preferences_spec.rb b/spec/features/profiles/user_edit_preferences_spec.rb index 3129e4bd952..c724de04043 100644 --- a/spec/features/profiles/user_edit_preferences_spec.rb +++ b/spec/features/profiles/user_edit_preferences_spec.rb @@ -1,10 +1,16 @@ # frozen_string_literal: true + require 'spec_helper' RSpec.describe 'User edit preferences profile', :js do + include StubLanguagesTranslationPercentage + + # Empty value doesn't change the levels + let(:language_percentage_levels) { nil } let(:user) { create(:user) } before do + stub_languages_translation_percentage(language_percentage_levels) stub_feature_flags(user_time_settings: true) sign_in(user) visit(profile_preferences_path) @@ -63,17 +69,4 @@ RSpec.describe 'User edit preferences profile', :js do expect(page).to have_content('Failed to save preferences.') end end - - describe 'User language' do - let(:user) { create(:user, preferred_language: :es) } - - it 'shows the user preferred language by default' do - expect(page).to have_select( - 'user[preferred_language]', - selected: 'Spanish - español', - options: Gitlab::I18n.selectable_locales.values, - visible: :all - ) - end - end end diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb index 4d7083c4ca7..6be6d3670d4 100644 --- a/spec/helpers/preferences_helper_spec.rb +++ b/spec/helpers/preferences_helper_spec.rb @@ -121,6 +121,20 @@ RSpec.describe PreferencesHelper do end end + describe '#language_choices' do + include StubLanguagesTranslationPercentage + + it 'lists all the selectable language options with their translation percent' do + stub_languages_translation_percentage(en: 100, es: 65) + stub_user(preferred_language: :en) + + expect(helper.language_choices).to eq([ + '<option selected="selected" value="en">English (100% translated)</option>', + '<option value="es">Spanish - español (65% translated)</option>' + ].join("\n")) + end + end + def stub_user(messages = {}) if messages.empty? allow(helper).to receive(:current_user).and_return(nil) diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb index ccff902d290..9b05c12ef57 100644 --- a/spec/lib/gitlab/email/receiver_spec.rb +++ b/spec/lib/gitlab/email/receiver_spec.rb @@ -15,6 +15,7 @@ RSpec.describe Gitlab::Email::Receiver do context 'when the email contains a valid email address in a header' do let(:handler) { double(:handler) } + let(:metadata) { receiver.mail_metadata } before do allow(handler).to receive(:execute) @@ -22,24 +23,38 @@ RSpec.describe Gitlab::Email::Receiver do allow(handler).to receive(:metrics_event) stub_incoming_email_setting(enabled: true, address: "incoming+%{key}@appmail.example.com") + + expect(receiver.mail_metadata.keys).to match_array(%i(mail_uid from_address to_address mail_key references delivered_to envelope_to x_envelope_to)) end context 'when in a Delivered-To header' do let(:email_raw) { fixture_file('emails/forwarded_new_issue.eml') } it_behaves_like 'correctly finds the mail key' + + it 'parses the metadata' do + expect(metadata[:delivered_to]). to eq(["incoming+gitlabhq/gitlabhq+auth_token@appmail.example.com", "support@example.com"]) + end end context 'when in an Envelope-To header' do let(:email_raw) { fixture_file('emails/envelope_to_header.eml') } it_behaves_like 'correctly finds the mail key' + + it 'parses the metadata' do + expect(metadata[:envelope_to]). to eq(["incoming+gitlabhq/gitlabhq+auth_token@appmail.example.com"]) + end end context 'when in an X-Envelope-To header' do let(:email_raw) { fixture_file('emails/x_envelope_to_header.eml') } it_behaves_like 'correctly finds the mail key' + + it 'parses the metadata' do + expect(metadata[:x_envelope_to]). to eq(["incoming+gitlabhq/gitlabhq+auth_token@appmail.example.com"]) + end end context 'when enclosed with angle brackets in an Envelope-To header' do diff --git a/spec/lib/gitlab/i18n_spec.rb b/spec/lib/gitlab/i18n_spec.rb index ee10739195a..aae4a13bd73 100644 --- a/spec/lib/gitlab/i18n_spec.rb +++ b/spec/lib/gitlab/i18n_spec.rb @@ -3,13 +3,18 @@ require 'spec_helper' RSpec.describe Gitlab::I18n do - let(:user) { create(:user, preferred_language: 'es') } + let(:user) { create(:user, preferred_language: :es) } describe '.selectable_locales' do - it 'does not return languages that should not be available in the UI' do - Gitlab::I18n::NOT_AVAILABLE_IN_UI.each do |language| - expect(described_class.selectable_locales).not_to include(language) - end + include StubLanguagesTranslationPercentage + + it 'does not return languages with low translation levels' do + stub_languages_translation_percentage(pt_BR: 0, en: 100, es: 65) + + expect(described_class.selectable_locales).to eq({ + 'en' => 'English', + 'es' => 'Spanish - español' + }) end end diff --git a/spec/lib/gitlab/prometheus/adapter_spec.rb b/spec/lib/gitlab/prometheus/adapter_spec.rb index 9d4806ea73b..259202178a2 100644 --- a/spec/lib/gitlab/prometheus/adapter_spec.rb +++ b/spec/lib/gitlab/prometheus/adapter_spec.rb @@ -58,8 +58,8 @@ RSpec.describe Gitlab::Prometheus::Adapter do context 'with cluster with prometheus integration' do let!(:prometheus_integration) { create(:clusters_integrations_prometheus, cluster: cluster) } - it 'returns the integration instead' do - expect(subject.prometheus_adapter).to eq(prometheus_integration) + it 'returns the application' do + expect(subject.prometheus_adapter).to eq(prometheus) end end end diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb index f74a89eaec5..549a273e2d7 100644 --- a/spec/models/clusters/applications/prometheus_spec.rb +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -13,16 +13,13 @@ RSpec.describe Clusters::Applications::Prometheus do include_examples 'cluster application initial status specs' describe 'after_destroy' do - context 'cluster type is project' do - let(:cluster) { create(:cluster, :with_installed_helm) } - let(:application) { create(:clusters_applications_prometheus, :installed, cluster: cluster) } + let(:cluster) { create(:cluster, :with_installed_helm) } + let(:application) { create(:clusters_applications_prometheus, :installed, cluster: cluster) } - it 'deactivates prometheus_service after destroy' do - expect(Clusters::Applications::DeactivateServiceWorker) - .to receive(:perform_async).with(cluster.id, 'prometheus') + it 'disables the corresponding integration' do + application.destroy! - application.destroy! - end + expect(cluster.integration_prometheus).not_to be_enabled end end @@ -31,11 +28,10 @@ RSpec.describe Clusters::Applications::Prometheus do let(:cluster) { create(:cluster, :with_installed_helm) } let(:application) { create(:clusters_applications_prometheus, :installing, cluster: cluster) } - it 'schedules post installation job' do - expect(Clusters::Applications::ActivateServiceWorker) - .to receive(:perform_async).with(cluster.id, 'prometheus') - + it 'enables the corresponding integration' do application.make_installed + + expect(cluster.integration_prometheus).to be_enabled end end @@ -44,11 +40,10 @@ RSpec.describe Clusters::Applications::Prometheus do let(:cluster) { create(:cluster, :with_installed_helm) } let(:application) { create(:clusters_applications_prometheus, :installing, cluster: cluster) } - it 'schedules post installation job' do - expect(Clusters::Applications::ActivateServiceWorker) - .to receive(:perform_async).with(cluster.id, 'prometheus') - + it 'enables the corresponding integration' do application.make_externally_installed! + + expect(cluster.integration_prometheus).to be_enabled end end @@ -338,42 +333,10 @@ RSpec.describe Clusters::Applications::Prometheus do describe 'alert manager token' do subject { create(:clusters_applications_prometheus) } - context 'when not set' do - it 'is empty by default' do - expect(subject.alert_manager_token).to be_nil - expect(subject.encrypted_alert_manager_token).to be_nil - expect(subject.encrypted_alert_manager_token_iv).to be_nil - end - - describe '#generate_alert_manager_token!' do - it 'generates a token' do - subject.generate_alert_manager_token! - - expect(subject.alert_manager_token).to match(/\A\h{32}\z/) - end - end - end - - context 'when set' do - let(:token) { SecureRandom.hex } - - before do - subject.update!(alert_manager_token: token) - end - - it 'reads the token' do - expect(subject.alert_manager_token).to eq(token) - expect(subject.encrypted_alert_manager_token).not_to be_nil - expect(subject.encrypted_alert_manager_token_iv).not_to be_nil - end - - describe '#generate_alert_manager_token!' do - it 'does not re-generate the token' do - subject.generate_alert_manager_token! - - expect(subject.alert_manager_token).to eq(token) - end - end + it 'is autogenerated on creation' do + expect(subject.alert_manager_token).to match(/\A\h{32}\z/) + expect(subject.encrypted_alert_manager_token).not_to be_nil + expect(subject.encrypted_alert_manager_token_iv).not_to be_nil end end end diff --git a/spec/models/clusters/integrations/prometheus_spec.rb b/spec/models/clusters/integrations/prometheus_spec.rb index a7be1673ce2..680786189ad 100644 --- a/spec/models/clusters/integrations/prometheus_spec.rb +++ b/spec/models/clusters/integrations/prometheus_spec.rb @@ -15,6 +15,62 @@ RSpec.describe Clusters::Integrations::Prometheus do it { is_expected.not_to allow_value(nil).for(:enabled) } end + describe 'after_destroy' do + subject(:integration) { create(:clusters_integrations_prometheus, cluster: cluster, enabled: true) } + + let(:cluster) { create(:cluster, :with_installed_helm) } + + it 'deactivates prometheus_service' do + expect(Clusters::Applications::DeactivateServiceWorker) + .to receive(:perform_async).with(cluster.id, 'prometheus') + + integration.destroy! + end + end + + describe 'after_save' do + subject(:integration) { create(:clusters_integrations_prometheus, cluster: cluster, enabled: enabled) } + + let(:cluster) { create(:cluster, :with_installed_helm) } + let(:enabled) { true } + + context 'when no change to enabled status' do + it 'does not touch project services' do + integration # ensure integration exists before we set the expectations + + expect(Clusters::Applications::DeactivateServiceWorker) + .not_to receive(:perform_async) + + expect(Clusters::Applications::ActivateServiceWorker) + .not_to receive(:perform_async) + + integration.update!(enabled: enabled) + end + end + + context 'when enabling' do + let(:enabled) { false } + + it 'deactivates prometheus_service' do + expect(Clusters::Applications::ActivateServiceWorker) + .to receive(:perform_async).with(cluster.id, 'prometheus') + + integration.update!(enabled: true) + end + end + + context 'when disabling' do + let(:enabled) { true } + + it 'activates prometheus_service' do + expect(Clusters::Applications::DeactivateServiceWorker) + .to receive(:perform_async).with(cluster.id, 'prometheus') + + integration.update!(enabled: false) + end + end + end + describe '#prometheus_client' do include_examples '#prometheus_client shared' do let(:factory) { :clusters_integrations_prometheus } diff --git a/spec/services/projects/prometheus/alerts/notify_service_spec.rb b/spec/services/projects/prometheus/alerts/notify_service_spec.rb index 26d8d3afd10..bfc8225b654 100644 --- a/spec/services/projects/prometheus/alerts/notify_service_spec.rb +++ b/spec/services/projects/prometheus/alerts/notify_service_spec.rb @@ -62,7 +62,7 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do end end - context 'with project specific cluster' do + context 'with project specific cluster using prometheus application' do where(:cluster_enabled, :status, :configured_token, :token_input, :result) do true | :installed | token | token | :success true | :installed | nil | nil | :success @@ -97,6 +97,40 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do end end + context 'with project specific cluster using prometheus integration' do + where(:cluster_enabled, :integration_enabled, :configured_token, :token_input, :result) do + true | true | token | token | :success + true | true | nil | nil | :success + true | true | token | 'x' | :failure + true | true | token | nil | :failure + true | false | token | token | :failure + false | true | token | token | :failure + false | nil | nil | token | :failure + end + + with_them do + before do + cluster.update!(enabled: cluster_enabled) + + unless integration_enabled.nil? + create(:clusters_integrations_prometheus, + cluster: cluster, + enabled: integration_enabled, + alert_manager_token: configured_token) + end + end + + case result = params[:result] + when :success + include_examples 'processes one firing and one resolved prometheus alerts' + when :failure + it_behaves_like 'alerts service responds with an error and takes no actions', :unauthorized + else + raise "invalid result: #{result.inspect}" + end + end + end + context 'without project specific cluster' do let_it_be(:cluster) { create(:cluster, enabled: true) } diff --git a/spec/support/stub_languages_translation_percentage.rb b/spec/support/stub_languages_translation_percentage.rb new file mode 100644 index 00000000000..a93316288b9 --- /dev/null +++ b/spec/support/stub_languages_translation_percentage.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module StubLanguagesTranslationPercentage + # Stubs the translation percentage of the i18n languages + # - When a `blank?` list is given no stubbing is done; + # - When the list is not empty, the languages in the list + # are stubbed with the given values, any other language + # will have the translation percent set to 0; + def stub_languages_translation_percentage(list = {}) + return if list.blank? + + expect(Gitlab::I18n) + .to receive(:percentage_translated_for) + .at_least(:once) + .and_wrap_original do |_original, code| + list.with_indifferent_access[code].to_i + end + end +end diff --git a/spec/workers/email_receiver_worker_spec.rb b/spec/workers/email_receiver_worker_spec.rb index 8bf7f3f552d..d26c08fb221 100644 --- a/spec/workers/email_receiver_worker_spec.rb +++ b/spec/workers/email_receiver_worker_spec.rb @@ -13,6 +13,7 @@ RSpec.describe EmailReceiverWorker, :mailer do it "calls the email receiver" do expect(Gitlab::Email::Receiver).to receive(:new).with(raw_message).and_call_original expect_any_instance_of(Gitlab::Email::Receiver).to receive(:execute) + expect(Sidekiq.logger).to receive(:info).with(hash_including(message: "Successfully processed message")).and_call_original described_class.new.perform(raw_message) end @@ -20,10 +21,11 @@ RSpec.describe EmailReceiverWorker, :mailer do context "when an error occurs" do before do allow_any_instance_of(Gitlab::Email::Receiver).to receive(:execute).and_raise(error) + expect(Sidekiq.logger).to receive(:error).with(hash_including('exception.class' => error.class.name)).and_call_original end context 'when the error is Gitlab::Email::EmptyEmailError' do - let(:error) { Gitlab::Email::EmptyEmailError } + let(:error) { Gitlab::Email::EmptyEmailError.new } it 'sends out a rejection email' do perform_enqueued_jobs do @@ -38,7 +40,7 @@ RSpec.describe EmailReceiverWorker, :mailer do end context 'when the error is Gitlab::Email::AutoGeneratedEmailError' do - let(:error) { Gitlab::Email::AutoGeneratedEmailError } + let(:error) { Gitlab::Email::AutoGeneratedEmailError.new } it 'does not send out any rejection email' do perform_enqueued_jobs do @@ -63,6 +65,21 @@ RSpec.describe EmailReceiverWorker, :mailer do expect(email.body.parts.last.to_s).to include("Could not deal with that") end end + + context 'when the error is ActiveRecord::StatementTimeout' do + let(:error) { ActiveRecord::StatementTimeout.new("Statement timeout") } + + it 'does not report the error to the sender' do + expect(Gitlab::ErrorTracking).to receive(:track_exception).with(error).and_call_original + + perform_enqueued_jobs do + described_class.new.perform(raw_message) + end + + email = ActionMailer::Base.deliveries.last + expect(email).to be_nil + end + end end end diff --git a/spec/workers/service_desk_email_receiver_worker_spec.rb b/spec/workers/service_desk_email_receiver_worker_spec.rb index d3bfa51348e..60fc951f627 100644 --- a/spec/workers/service_desk_email_receiver_worker_spec.rb +++ b/spec/workers/service_desk_email_receiver_worker_spec.rb @@ -9,11 +9,12 @@ RSpec.describe ServiceDeskEmailReceiverWorker, :mailer do context 'when service_desk_email config is enabled' do before do - stub_service_desk_email_setting(enabled: true, address: 'foo') + stub_service_desk_email_setting(enabled: true, address: 'support+%{key}@example.com') end it 'does not ignore the email' do - expect(Gitlab::Email::ServiceDeskReceiver).to receive(:new) + expect(Gitlab::Email::ServiceDeskReceiver).to receive(:new).and_call_original + expect(Sidekiq.logger).to receive(:error).with(hash_including('exception.class' => Gitlab::Email::ProjectNotFound.to_s)).and_call_original worker.perform(email) end @@ -23,6 +24,7 @@ RSpec.describe ServiceDeskEmailReceiverWorker, :mailer do allow_next_instance_of(Gitlab::Email::ServiceDeskReceiver) do |receiver| allow(receiver).to receive(:find_handler).and_return(nil) end + expect(Sidekiq.logger).to receive(:error).with(hash_including('exception.class' => Gitlab::Email::UnknownIncomingEmail.to_s)).and_call_original end it 'sends a rejection email' do |