diff options
42 files changed, 466 insertions, 195 deletions
@@ -345,9 +345,9 @@ group :development, :test do # Generate Fake data gem 'ffaker', '~> 2.10' - gem 'capybara', '~> 2.16.1' - gem 'capybara-screenshot', '~> 1.0.18' - gem 'selenium-webdriver', '~> 3.12' + gem 'capybara', '~> 2.18.0' + gem 'capybara-screenshot', '~> 1.0.22' + gem 'selenium-webdriver', '~> 3.141' gem 'spring', '~> 2.0.0' gem 'spring-commands-rspec', '~> 1.0.4' diff --git a/Gemfile.lock b/Gemfile.lock index baa7be6258a..c1d1a50799f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -100,13 +100,13 @@ GEM bundler (~> 1.2) thor (~> 0.18) byebug (9.1.0) - capybara (2.16.1) + capybara (2.18.0) addressable mini_mime (>= 0.1.3) nokogiri (>= 1.3.3) rack (>= 1.0.0) rack-test (>= 0.5.4) - xpath (~> 2.0) + xpath (>= 2.0, < 4.0) capybara-screenshot (1.0.22) capybara (>= 1.0, < 4) launchy @@ -488,7 +488,7 @@ GEM net-ssh (5.0.1) netrc (0.11.0) nio4r (2.3.1) - nokogiri (1.10.1) + nokogiri (1.10.2) mini_portile2 (~> 2.4.0) nokogumbo (1.5.0) nokogiri @@ -706,7 +706,7 @@ GEM redis-store (>= 1.2, < 2) redis-store (1.6.0) redis (>= 2.2, < 5) - regexp_parser (1.3.0) + regexp_parser (1.4.0) regexp_property_values (0.3.4) representable (3.0.4) declarative (< 0.1.0) @@ -815,9 +815,9 @@ GEM seed-fu (2.3.7) activerecord (>= 3.1) activesupport (>= 3.1) - selenium-webdriver (3.12.0) + selenium-webdriver (3.141.0) childprocess (~> 0.5) - rubyzip (~> 1.2) + rubyzip (~> 1.2, >= 1.2.2) sentry-raven (2.9.0) faraday (>= 0.7.6, < 1.0) settingslogic (2.0.9) @@ -943,8 +943,8 @@ GEM rinku with_env (1.1.0) xml-simple (1.1.5) - xpath (2.1.0) - nokogiri (~> 1.3) + xpath (3.2.0) + nokogiri (~> 1.8) PLATFORMS ruby @@ -974,8 +974,8 @@ DEPENDENCIES browser (~> 2.5) bullet (~> 5.5.0) bundler-audit (~> 0.5.0) - capybara (~> 2.16.1) - capybara-screenshot (~> 1.0.18) + capybara (~> 2.18.0) + capybara-screenshot (~> 1.0.22) carrierwave (~> 1.3) charlock_holmes (~> 0.7.5) chronic (~> 0.10.2) @@ -1146,7 +1146,7 @@ DEPENDENCIES sass-rails (~> 5.0.6) scss_lint (~> 0.56.0) seed-fu (~> 2.3.7) - selenium-webdriver (~> 3.12) + selenium-webdriver (~> 3.141) sentry-raven (~> 2.7) settingslogic (~> 2.0.9) sham_rack (~> 1.3.6) diff --git a/app/assets/stylesheets/pages/pipeline_schedules.scss b/app/assets/stylesheets/pages/pipeline_schedules.scss index 617b3db2fae..85c4902eee2 100644 --- a/app/assets/stylesheets/pages/pipeline_schedules.scss +++ b/app/assets/stylesheets/pages/pipeline_schedules.scss @@ -1,9 +1,4 @@ -.js-pipeline-schedule-form { - .dropdown-select, - .dropdown-menu-toggle { - width: 100% !important; - } - +.pipeline-schedule-form { .gl-field-error { margin: 10px 0 0; } diff --git a/app/assets/stylesheets/pages/reports.scss b/app/assets/stylesheets/pages/reports.scss index f7619ccbd20..94da72622af 100644 --- a/app/assets/stylesheets/pages/reports.scss +++ b/app/assets/stylesheets/pages/reports.scss @@ -52,11 +52,6 @@ .report-block-list-icon .loading-container { position: relative; left: -2px; - // needed to make the next element align with the - // elements below that have a svg with 16px width - .fa-spinner { - width: 16px; - } } } diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index eb6ddaac871..2f9b4c4eaa2 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -198,7 +198,7 @@ class ApplicationSetting < ApplicationRecord validates_each :restricted_visibility_levels do |record, attr, value| value&.each do |level| unless Gitlab::VisibilityLevel.options.value?(level) - record.errors.add(attr, "'#{level}' is not a valid visibility level") + record.errors.add(attr, _("'%{level}' is not a valid visibility level") % { level: level }) end end end @@ -206,7 +206,7 @@ class ApplicationSetting < ApplicationRecord validates_each :import_sources do |record, attr, value| value&.each do |source| unless Gitlab::ImportSources.options.value?(source) - record.errors.add(attr, "'#{source}' is not a import source") + record.errors.add(attr, _("'%{source}' is not a import source") % { source: source }) end end end diff --git a/app/models/concerns/group_descendant.rb b/app/models/concerns/group_descendant.rb index 05cd4265133..cfffd845e43 100644 --- a/app/models/concerns/group_descendant.rb +++ b/app/models/concerns/group_descendant.rb @@ -22,7 +22,7 @@ module GroupDescendant return [] if descendants.empty? unless descendants.all? { |hierarchy| hierarchy.is_a?(GroupDescendant) } - raise ArgumentError.new('element is not a hierarchy') + raise ArgumentError.new(_('element is not a hierarchy')) end all_hierarchies = descendants.map do |descendant| @@ -56,7 +56,7 @@ module GroupDescendant end if parent.nil? && hierarchy_top.present? - raise ArgumentError.new('specified top is not part of the tree') + raise ArgumentError.new(_('specified top is not part of the tree')) end if parent && parent != hierarchy_top diff --git a/app/models/concerns/token_authenticatable_strategies/base.rb b/app/models/concerns/token_authenticatable_strategies/base.rb index df14e6e4754..aafd0b538a3 100644 --- a/app/models/concerns/token_authenticatable_strategies/base.rb +++ b/app/models/concerns/token_authenticatable_strategies/base.rb @@ -41,7 +41,7 @@ module TokenAuthenticatableStrategies def self.fabricate(model, field, options) if options[:digest] && options[:encrypted] - raise ArgumentError, 'Incompatible options set!' + raise ArgumentError, _('Incompatible options set!') end if options[:digest] diff --git a/app/models/concerns/token_authenticatable_strategies/encrypted.rb b/app/models/concerns/token_authenticatable_strategies/encrypted.rb index 2c7fa2c5b3c..4728cb658dc 100644 --- a/app/models/concerns/token_authenticatable_strategies/encrypted.rb +++ b/app/models/concerns/token_authenticatable_strategies/encrypted.rb @@ -13,7 +13,7 @@ module TokenAuthenticatableStrategies elsif migrating? find_by_plaintext_token(token, unscoped) else - raise ArgumentError, "Unknown encryption strategy: #{encrypted_strategy}!" + raise ArgumentError, _("Unknown encryption strategy: %{encrypted_strategy}!") % { encrypted_strategy: encrypted_strategy } end end @@ -32,7 +32,7 @@ module TokenAuthenticatableStrategies return super if instance.has_attribute?(encrypted_field) if required? - raise ArgumentError, 'Using required encryption strategy when encrypted field is missing!' + raise ArgumentError, _('Using required encryption strategy when encrypted field is missing!') else insecure_strategy.ensure_token(instance) end @@ -74,7 +74,7 @@ module TokenAuthenticatableStrategies value = value.call if value.is_a?(Proc) unless value.in?([:required, :optional, :migrating]) - raise ArgumentError, 'encrypted: needs to be a :required, :optional or :migrating!' + raise ArgumentError, _('encrypted: needs to be a :required, :optional or :migrating!') end value diff --git a/app/models/milestone.rb b/app/models/milestone.rb index b4aad9e512e..787600569fa 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -291,22 +291,22 @@ class Milestone < ApplicationRecord end title_exists = relation.find_by_title(title) - errors.add(:title, "already being used for another group or project milestone.") if title_exists + errors.add(:title, _("already being used for another group or project milestone.")) if title_exists end # Milestone should be either a project milestone or a group milestone def milestone_type_check if group_id && project_id field = project_id_changed? ? :project_id : :group_id - errors.add(field, "milestone should belong either to a project or a group.") + errors.add(field, _("milestone should belong either to a project or a group.")) end end def milestone_format_reference(format = :iid) - raise ArgumentError, 'Unknown format' unless [:iid, :name].include?(format) + raise ArgumentError, _('Unknown format') unless [:iid, :name].include?(format) if group_milestone? && format == :iid - raise ArgumentError, 'Cannot refer to a group milestone by an internal id!' + raise ArgumentError, _('Cannot refer to a group milestone by an internal id!') end if format == :name && !name.include?('"') @@ -322,7 +322,7 @@ class Milestone < ApplicationRecord def start_date_should_be_less_than_due_date if due_date <= start_date - errors.add(:due_date, "must be greater than start date") + errors.add(:due_date, _("must be greater than start date")) end end diff --git a/app/models/project.rb b/app/models/project.rb index c838df03c0d..2fb6f5cb6a7 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -313,7 +313,7 @@ class Project < ApplicationRecord validates :description, length: { maximum: 2000 }, allow_blank: true validates :ci_config_path, format: { without: %r{(\.{2}|\A/)}, - message: 'cannot include leading slash or directory traversal.' }, + message: _('cannot include leading slash or directory traversal.') }, length: { maximum: 255 }, allow_blank: true validates :name, @@ -420,13 +420,13 @@ class Project < ApplicationRecord enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 } chronic_duration_attr :build_timeout_human_readable, :build_timeout, - default: 3600, error_message: 'Maximum job timeout has a value which could not be accepted' + default: 3600, error_message: _('Maximum job timeout has a value which could not be accepted') validates :build_timeout, allow_nil: true, numericality: { greater_than_or_equal_to: 10.minutes, less_than: 1.month, only_integer: true, - message: 'needs to be beetween 10 minutes and 1 month' } + message: _('needs to be beetween 10 minutes and 1 month') } # Used by Projects::CleanupService to hold a map of rewritten object IDs mount_uploader :bfg_object_map, AttachmentUploader @@ -850,7 +850,7 @@ class Project < ApplicationRecord def mark_stuck_remote_mirrors_as_failed! remote_mirrors.stuck.update_all( update_status: :failed, - last_error: 'The remote mirror took to long to complete.', + last_error: _('The remote mirror took to long to complete.'), last_update_at: Time.now ) end @@ -887,14 +887,14 @@ class Project < ApplicationRecord level_name = Gitlab::VisibilityLevel.level_name(self.visibility_level).downcase group_level_name = Gitlab::VisibilityLevel.level_name(self.group.visibility_level).downcase - self.errors.add(:visibility_level, "#{level_name} is not allowed in a #{group_level_name} group.") + self.errors.add(:visibility_level, _("%{level_name} is not allowed in a %{group_level_name} group.") % { level_name: level_name, group_level_name: group_level_name }) end def visibility_level_allowed_as_fork return if visibility_level_allowed_as_fork? level_name = Gitlab::VisibilityLevel.level_name(self.visibility_level).downcase - self.errors.add(:visibility_level, "#{level_name} is not allowed since the fork source project has lower visibility.") + self.errors.add(:visibility_level, _("%{level_name} is not allowed since the fork source project has lower visibility.") % { level_name: level_name }) end def check_wiki_path_conflict @@ -903,7 +903,7 @@ class Project < ApplicationRecord path_to_check = path.ends_with?('.wiki') ? path.chomp('.wiki') : "#{path}.wiki" if Project.where(namespace_id: namespace_id, path: path_to_check).exists? - errors.add(:name, 'has already been taken') + errors.add(:name, _('has already been taken')) end end @@ -923,7 +923,7 @@ class Project < ApplicationRecord return unless pages_https_only? unless pages_domains.all?(&:https?) - errors.add(:pages_https_only, "cannot be enabled unless all domains have TLS certificates") + errors.add(:pages_https_only, _("cannot be enabled unless all domains have TLS certificates")) end end @@ -1203,7 +1203,7 @@ class Project < ApplicationRecord def valid_repo? repository.exists? rescue - errors.add(:path, 'Invalid repository path') + errors.add(:path, _('Invalid repository path')) false end @@ -1294,7 +1294,7 @@ class Project < ApplicationRecord # Check if repository with same path already exists on disk we can # skip this for the hashed storage because the path does not change if legacy_storage? && repository_with_same_path_already_exists? - errors.add(:base, 'There is already a repository with that name on disk') + errors.add(:base, _('There is already a repository with that name on disk')) return false end @@ -1316,7 +1316,7 @@ class Project < ApplicationRecord repository.after_create true else - errors.add(:base, 'Failed to create repository via gitlab-shell') + errors.add(:base, _('Failed to create repository via gitlab-shell')) false end end @@ -1392,7 +1392,7 @@ class Project < ApplicationRecord ProjectCacheWorker.perform_async(self.id, [], [:commit_count]) reload_default_branch else - errors.add(:base, "Could not change HEAD: branch '#{branch}' does not exist") + errors.add(:base, _("Could not change HEAD: branch '%{branch}' does not exist") % { branch: branch }) false end end @@ -1444,7 +1444,7 @@ class Project < ApplicationRecord ProjectWiki.new(self, self.owner).wiki true rescue ProjectWiki::CouldNotCreateWikiError - errors.add(:base, 'Failed create wiki') + errors.add(:base, _('Failed create wiki')) false end @@ -1933,7 +1933,7 @@ class Project < ApplicationRecord # # @param [Symbol] feature that needs to be rolled out for the project (:repository, :attachments) def hashed_storage?(feature) - raise ArgumentError, "Invalid feature" unless HASHED_STORAGE_FEATURES.include?(feature) + raise ArgumentError, _("Invalid feature") unless HASHED_STORAGE_FEATURES.include?(feature) self.storage_version && self.storage_version >= HASHED_STORAGE_FEATURES[feature] end @@ -2165,7 +2165,7 @@ class Project < ApplicationRecord return if skip_disk_validation if repository_storage.blank? || repository_with_same_path_already_exists? - errors.add(:base, 'There is already a repository with that name on disk') + errors.add(:base, _('There is already a repository with that name on disk')) throw :abort end end @@ -2211,7 +2211,7 @@ class Project < ApplicationRecord errors.delete(error) end - errors.add(:base, "The project is still being deleted. Please try again later.") + errors.add(:base, _("The project is still being deleted. Please try again later.")) end def pending_delete_twin diff --git a/app/models/project_group_link.rb b/app/models/project_group_link.rb index 58b555c3581..feaf172d48d 100644 --- a/app/models/project_group_link.rb +++ b/app/models/project_group_link.rb @@ -14,7 +14,7 @@ class ProjectGroupLink < ApplicationRecord validates :project_id, presence: true validates :group, presence: true - validates :group_id, uniqueness: { scope: [:project_id], message: "already shared with this group" } + validates :group_id, uniqueness: { scope: [:project_id], message: _("already shared with this group") } validates :group_access, presence: true validates :group_access, inclusion: { in: Gitlab::Access.values }, presence: true validate :different_group @@ -44,7 +44,7 @@ class ProjectGroupLink < ApplicationRecord group_ids = project_group.ancestors.map(&:id).push(project_group.id) if group_ids.include?(self.group.id) - errors.add(:base, "Project cannot be shared with the group it is in or one of its ancestors.") + errors.add(:base, _("Project cannot be shared with the group it is in or one of its ancestors.")) end end diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index cc5f1207653..3e28dc23782 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -11,7 +11,7 @@ class AsanaService < Service end def description - 'Asana - Teamwork without email' + s_('AsanaService|Asana - Teamwork without email') end def help @@ -36,13 +36,13 @@ http://app.asana.com/-/account_api' { type: 'text', name: 'api_key', - placeholder: 'User Personal Access Token. User must have access to task, all comments will be attributed to this user.', + placeholder: s_('AsanaService|User Personal Access Token. User must have access to task, all comments will be attributed to this user.'), required: true }, { type: 'text', name: 'restrict_to_branch', - placeholder: 'Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches.' + placeholder: s_('AsanaService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches.') } ] end @@ -73,7 +73,7 @@ http://app.asana.com/-/account_api' project_name = project.full_name data[:commits].each do |commit| - push_msg = "#{user} pushed to branch #{branch} of #{project_name} ( #{commit[:url]} ):" + push_msg = s_("AsanaService|%{user} pushed to branch %{branch} of %{project_name} ( %{commit_url} ):") % { user: user, branch: branch, project_name: project_name, commit_url: commit[:url] } check_commit(commit[:message], push_msg) end end diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb index 71f5607dbdb..dfeb21680a9 100644 --- a/app/models/project_services/bamboo_service.rb +++ b/app/models/project_services/bamboo_service.rb @@ -31,15 +31,15 @@ class BambooService < CiService end def title - 'Atlassian Bamboo CI' + s_('BambooService|Atlassian Bamboo CI') end def description - 'A continuous integration and build server' + s_('BambooService|A continuous integration and build server') end def help - 'You must set up automatic revision labeling and a repository trigger in Bamboo.' + s_('BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo.') end def self.to_param @@ -49,11 +49,11 @@ class BambooService < CiService def fields [ { type: 'text', name: 'bamboo_url', - placeholder: 'Bamboo root URL like https://bamboo.example.com', required: true }, + placeholder: s_('BambooService|Bamboo root URL like https://bamboo.example.com'), required: true }, { type: 'text', name: 'build_key', - placeholder: 'Bamboo build plan key like KEY', required: true }, + placeholder: s_('BambooService|Bamboo build plan key like KEY'), required: true }, { type: 'text', name: 'username', - placeholder: 'A user with API access, if applicable' }, + placeholder: s_('BambooService|A user with API access, if applicable') }, { type: 'password', name: 'password' } ] end diff --git a/app/models/project_services/discord_service.rb b/app/models/project_services/discord_service.rb index 21afd14dbff..405676792de 100644 --- a/app/models/project_services/discord_service.rb +++ b/app/models/project_services/discord_service.rb @@ -4,11 +4,11 @@ require "discordrb/webhooks" class DiscordService < ChatNotificationService def title - "Discord Notifications" + s_("DiscordService|Discord Notifications") end def description - "Receive event notifications in Discord" + s_("DiscordService|Receive event notifications in Discord") end def self.to_param diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index fb73d430fb1..45de64a9990 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -7,11 +7,11 @@ class EmailsOnPushService < Service validates :recipients, presence: true, if: :valid_recipients? def title - 'Emails on push' + s_('EmailsOnPushService|Emails on push') end def description - 'Email the commits and diff of each push to a list of recipients.' + s_('EmailsOnPushService|Email the commits and diff of each push to a list of recipients.') end def self.to_param @@ -45,11 +45,11 @@ class EmailsOnPushService < Service def fields domains = Notify.allowed_email_domains.map { |domain| "user@#{domain}" }.join(", ") [ - { type: 'checkbox', name: 'send_from_committer_email', title: "Send from committer", - help: "Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. #{domains})." }, - { type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs", - help: "Don't include possibly sensitive code diffs in notification body." }, - { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' } + { type: 'checkbox', name: 'send_from_committer_email', title: s_("EmailsOnPushService|Send from committer"), + help: s_("EmailsOnPushService|Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. %{domains}).") % { domains: domains } }, + { type: 'checkbox', name: 'disable_diffs', title: s_("EmailsOnPushService|Disable code diffs"), + help: s_("EmailsOnPushService|Don't include possibly sensitive code diffs in notification body.") }, + { type: 'textarea', name: 'recipients', placeholder: s_('EmailsOnPushService|Emails separated by whitespace') } ] end end diff --git a/app/models/project_services/external_wiki_service.rb b/app/models/project_services/external_wiki_service.rb index d2835c6ac82..593ce69b0fd 100644 --- a/app/models/project_services/external_wiki_service.rb +++ b/app/models/project_services/external_wiki_service.rb @@ -6,11 +6,11 @@ class ExternalWikiService < Service validates :external_wiki_url, presence: true, public_url: true, if: :activated? def title - 'External Wiki' + s_('ExternalWikiService|External Wiki') end def description - 'Replaces the link to the internal wiki with a link to an external wiki.' + s_('ExternalWikiService|Replaces the link to the internal wiki with a link to an external wiki.') end def self.to_param @@ -19,7 +19,7 @@ class ExternalWikiService < Service def fields [ - { type: 'text', name: 'external_wiki_url', placeholder: 'The URL of the external Wiki', required: true } + { type: 'text', name: 'external_wiki_url', placeholder: s_('ExternalWikiService|The URL of the external Wiki'), required: true } ] end diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb index 76624263aab..094488cb431 100644 --- a/app/models/project_services/flowdock_service.rb +++ b/app/models/project_services/flowdock_service.rb @@ -9,7 +9,7 @@ class FlowdockService < Service end def description - 'Flowdock is a collaboration web app for technical teams.' + s_('FlowdockService|Flowdock is a collaboration web app for technical teams.') end def self.to_param @@ -18,7 +18,7 @@ class FlowdockService < Service def fields [ - { type: 'text', name: 'token', placeholder: 'Flowdock Git source token', required: true } + { type: 'text', name: 'token', placeholder: s_('FlowdockService|Flowdock Git source token'), required: true } ] end diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 81302c516c2..ebf28dc842c 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -11,7 +11,7 @@ class JiraService < IssueTrackerService validates :password, presence: true, if: :activated? validates :jira_issue_transition_id, - format: { with: Gitlab::Regex.jira_transition_id_regex, message: "transition ids can have only numbers which can be split with , or ;" }, + format: { with: Gitlab::Regex.jira_transition_id_regex, message: s_("JiraService|transition ids can have only numbers which can be split with , or ;") }, allow_blank: true # JIRA cloud version is deprecating authentication via username and password. @@ -86,7 +86,7 @@ class JiraService < IssueTrackerService if self.properties && self.properties['description'].present? self.properties['description'] else - 'Jira issue tracker' + s_('JiraService|Jira issue tracker') end end @@ -96,11 +96,11 @@ class JiraService < IssueTrackerService def fields [ - { type: 'text', name: 'url', title: 'Web URL', placeholder: 'https://jira.example.com', required: true }, - { type: 'text', name: 'api_url', title: 'JIRA API URL', placeholder: 'If different from Web URL' }, - { type: 'text', name: 'username', title: 'Username or Email', placeholder: 'Use a username for server version and an email for cloud version', required: true }, - { type: 'password', name: 'password', title: 'Password or API token', placeholder: 'Use a password for server version and an API token for cloud version', required: true }, - { type: 'text', name: 'jira_issue_transition_id', title: 'Transition ID(s)', placeholder: 'Use , or ; to separate multiple transition IDs' } + { type: 'text', name: 'url', title: s_('JiraService|Web URL'), placeholder: 'https://jira.example.com', required: true }, + { type: 'text', name: 'api_url', title: s_('JiraService|JIRA API URL'), placeholder: s_('JiraService|If different from Web URL') }, + { type: 'text', name: 'username', title: s_('JiraService|Username or Email'), placeholder: s_('JiraService|Use a username for server version and an email for cloud version'), required: true }, + { type: 'password', name: 'password', title: s_('JiraService|Password or API token'), placeholder: s_('JiraService|Use a password for server version and an API token for cloud version'), required: true }, + { type: 'text', name: 'jira_issue_transition_id', title: s_('JiraService|Transition ID(s)'), placeholder: s_('JiraService|Use , or ; to separate multiple transition IDs') } ] end @@ -139,7 +139,7 @@ class JiraService < IssueTrackerService def create_cross_reference_note(mentioned, noteable, author) unless can_cross_reference?(noteable) - return "Events for #{noteable.model_name.plural.humanize(capitalize: false)} are disabled." + return s_("JiraService|Events for %{noteable_model_name} are disabled.") % { noteable_model_name: noteable.model_name.plural.humanize(capitalize: false) } end jira_issue = jira_request { client.Issue.find(mentioned.id) } @@ -338,9 +338,9 @@ class JiraService < IssueTrackerService def self.event_description(event) case event when "merge_request", "merge_request_events" - "JIRA comments will be created when an issue gets referenced in a merge request." + s_("JiraService|JIRA comments will be created when an issue gets referenced in a merge request.") when "commit", "commit_events" - "JIRA comments will be created when an issue gets referenced in a commit." + s_("JiraService|JIRA comments will be created when an issue gets referenced in a commit.") end end end diff --git a/app/models/project_services/pipelines_email_service.rb b/app/models/project_services/pipelines_email_service.rb index d60a6a7efa3..7ba69370f14 100644 --- a/app/models/project_services/pipelines_email_service.rb +++ b/app/models/project_services/pipelines_email_service.rb @@ -10,11 +10,11 @@ class PipelinesEmailService < Service end def title - 'Pipelines emails' + _('Pipelines emails') end def description - 'Email the pipelines status to a list of recipients.' + _('Email the pipelines status to a list of recipients.') end def self.to_param @@ -51,7 +51,7 @@ class PipelinesEmailService < Service [ { type: 'textarea', name: 'recipients', - placeholder: 'Emails separated by comma', + placeholder: _('Emails separated by comma'), required: true }, { type: 'checkbox', name: 'notify_only_broken_pipelines' } diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb index 617e502b639..c15993bdc06 100644 --- a/app/models/project_services/pivotaltracker_service.rb +++ b/app/models/project_services/pivotaltracker_service.rb @@ -11,7 +11,7 @@ class PivotaltrackerService < Service end def description - 'Project Management Software (Source Commits Endpoint)' + s_('PivotalTrackerService|Project Management Software (Source Commits Endpoint)') end def self.to_param @@ -23,14 +23,14 @@ class PivotaltrackerService < Service { type: 'text', name: 'token', - placeholder: 'Pivotal Tracker API token.', + placeholder: s_('PivotalTrackerService|Pivotal Tracker API token.'), required: true }, { type: 'text', name: 'restrict_to_branch', - placeholder: 'Comma-separated list of branches which will be ' \ - 'automatically inspected. Leave blank to include all branches.' + placeholder: s_('PivotalTrackerService|Comma-separated list of branches which will be ' \ + 'automatically inspected. Leave blank to include all branches.') } ] end diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb index 4e48c348b45..0d35bab7f80 100644 --- a/app/models/project_services/pushover_service.rb +++ b/app/models/project_services/pushover_service.rb @@ -11,7 +11,7 @@ class PushoverService < Service end def description - 'Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop.' + s_('PushoverService|Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop.') end def self.to_param @@ -20,15 +20,15 @@ class PushoverService < Service def fields [ - { type: 'text', name: 'api_key', placeholder: 'Your application key', required: true }, - { type: 'text', name: 'user_key', placeholder: 'Your user key', required: true }, - { type: 'text', name: 'device', placeholder: 'Leave blank for all active devices' }, + { type: 'text', name: 'api_key', placeholder: s_('PushoverService|Your application key'), required: true }, + { type: 'text', name: 'user_key', placeholder: s_('PushoverService|Your user key'), required: true }, + { type: 'text', name: 'device', placeholder: s_('PushoverService|Leave blank for all active devices') }, { type: 'select', name: 'priority', required: true, choices: [ - ['Lowest Priority', -2], - ['Low Priority', -1], - ['Normal Priority', 0], - ['High Priority', 1] + [s_('PushoverService|Lowest Priority'), -2], + [s_('PushoverService|Low Priority'), -1], + [s_('PushoverService|Normal Priority'), 0], + [s_('PushoverService|High Priority'), 1] ], default_choice: 0 }, { type: 'select', name: 'sound', choices: @@ -73,15 +73,15 @@ class PushoverService < Service message = if Gitlab::Git.blank_ref?(before) - "#{data[:user_name]} pushed new branch \"#{ref}\"." + s_("PushoverService|%{user_name} pushed new branch \"%{ref}\".") % { user_name: data[:user_name], ref: ref } elsif Gitlab::Git.blank_ref?(after) - "#{data[:user_name]} deleted branch \"#{ref}\"." + s_("PushoverService|%{user_name} deleted branch \"%{ref}\".") % { user_name: data[:user_name], ref: ref } else - "#{data[:user_name]} push to branch \"#{ref}\"." + s_("PushoverService|%{user_name} push to branch \"%{ref}\".") % { user_name: data[:user_name], ref: ref } end if data[:total_commits_count] > 0 - message = [message, "Total commits count: #{data[:total_commits_count]}"].join("\n") + message = [message, s_("PushoverService|Total commits count: %{total_commits_count}") % { total_commits_count: data[:total_commits_count] }].join("\n") end pushover_data = { @@ -92,7 +92,7 @@ class PushoverService < Service title: "#{project.full_name}", message: message, url: data[:project][:web_url], - url_title: "See project #{project.full_name}" + url_title: s_("PushoverService|See project %{project_full_name}") % { project_full_name: project.full_name } } # Sound parameter MUST NOT be sent to API if not selected diff --git a/app/models/u2f_registration.rb b/app/models/u2f_registration.rb index b4645462314..81415eb383b 100644 --- a/app/models/u2f_registration.rb +++ b/app/models/u2f_registration.rb @@ -19,7 +19,7 @@ class U2fRegistration < ApplicationRecord user: user, name: params[:name]) rescue JSON::ParserError, NoMethodError, ArgumentError - registration.errors.add(:base, 'Your U2F device did not send a valid JSON response.') + registration.errors.add(:base, _('Your U2F device did not send a valid JSON response.')) rescue U2F::Error => e registration.errors.add(:base, e.message) end diff --git a/app/models/upload.rb b/app/models/upload.rb index 9bffdcdb2e7..ca74f16b3b8 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -45,7 +45,7 @@ class Upload < ApplicationRecord end def absolute_path - raise ObjectStorage::RemoteStoreError, "Remote object has no absolute path." unless local? + raise ObjectStorage::RemoteStoreError, _("Remote object has no absolute path.") unless local? return path unless relative_path? uploader_class.absolute_path(self) @@ -71,10 +71,10 @@ class Upload < ApplicationRecord # Help sysadmins find missing upload files if persisted? && !exist if Gitlab::Sentry.enabled? - Raven.capture_message("Upload file does not exist", extra: self.attributes) + Raven.capture_message(_("Upload file does not exist"), extra: self.attributes) end - Gitlab::Metrics.counter(:upload_file_does_not_exist_total, 'The number of times an upload record could not find its file').increment + Gitlab::Metrics.counter(:upload_file_does_not_exist_total, _('The number of times an upload record could not find its file')).increment end exist diff --git a/app/models/user.rb b/app/models/user.rb index d3524bfd6ae..551eb58a4de 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -517,7 +517,7 @@ class User < ApplicationRecord def ghost email = 'ghost%s@example.com' unique_internal(where(ghost: true), 'ghost', email) do |u| - u.bio = 'This is a "Ghost User", created to hold all issues authored by users that have since been deleted. This user cannot be removed.' + u.bio = _('This is a "Ghost User", created to hold all issues authored by users that have since been deleted. This user cannot be removed.') u.name = 'Ghost User' end end @@ -537,20 +537,16 @@ class User < ApplicationRecord username end - def self.internal_attributes - [:ghost] - end - def internal? - self.class.internal_attributes.any? { |a| self[a] } + ghost? end def self.internal - where(Hash[internal_attributes.zip([true] * internal_attributes.size)]) + where(ghost: true) end def self.non_internal - where(internal_attributes.map { |attr| "#{attr} IS NOT TRUE" }.join(" AND ")) + where('ghost IS NOT TRUE') end # @@ -626,32 +622,32 @@ class User < ApplicationRecord def namespace_move_dir_allowed if namespace&.any_project_has_container_registry_tags? - errors.add(:username, 'cannot be changed if a personal project has container registry tags.') + errors.add(:username, _('cannot be changed if a personal project has container registry tags.')) end end def unique_email if !emails.exists?(email: email) && Email.exists?(email: email) - errors.add(:email, 'has already been taken') + errors.add(:email, _('has already been taken')) end end def owns_notification_email return if temp_oauth_email? - errors.add(:notification_email, "is not an email you own") unless all_emails.include?(notification_email) + errors.add(:notification_email, _("is not an email you own")) unless all_emails.include?(notification_email) end def owns_public_email return if public_email.blank? - errors.add(:public_email, "is not an email you own") unless all_emails.include?(public_email) + errors.add(:public_email, _("is not an email you own")) unless all_emails.include?(public_email) end def owns_commit_email return if read_attribute(:commit_email).blank? - errors.add(:commit_email, "is not an email you own") unless verified_emails.include?(commit_email) + errors.add(:commit_email, _("is not an email you own")) unless verified_emails.include?(commit_email) end # Define commit_email-related attribute methods explicitly instead of relying diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 909da4316d0..cd4c7895587 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -31,7 +31,9 @@ class WikiPage pages.each_with_object([]) do |page, grouped_pages| next grouped_pages << page unless page.directory.present? - directory = grouped_pages.find { |dir| dir.slug == page.directory } + directory = grouped_pages.find do |obj| + obj.is_a?(WikiDirectory) && obj.slug == page.directory + end next directory.pages << page if directory diff --git a/app/services/clusters/applications/install_service.rb b/app/services/clusters/applications/install_service.rb index 1f62b3eb4de..b37ac510ff4 100644 --- a/app/services/clusters/applications/install_service.rb +++ b/app/services/clusters/applications/install_service.rb @@ -7,6 +7,13 @@ module Clusters return unless app.scheduled? app.make_installing! + + install + end + + private + + def install log_event(:begin_install) helm_api.install(install_command) @@ -18,7 +25,7 @@ module Clusters app.make_errored!("Kubernetes error: #{e.error_code}") rescue StandardError => e log_error(e) - app.make_errored!("Can't start installation process.") + app.make_errored!('Failed to install.') end end end diff --git a/app/services/clusters/applications/patch_service.rb b/app/services/clusters/applications/patch_service.rb index c3d317e226b..977a5e91041 100644 --- a/app/services/clusters/applications/patch_service.rb +++ b/app/services/clusters/applications/patch_service.rb @@ -8,6 +8,12 @@ module Clusters app.make_updating! + patch + end + + private + + def patch log_event(:begin_patch) helm_api.update(update_command) @@ -16,10 +22,10 @@ module Clusters ClusterWaitForAppInstallationWorker::INTERVAL, app.name, app.id) rescue Kubeclient::HttpError => e log_error(e) - app.make_update_errored!("Kubernetes error: #{e.error_code}") + app.make_errored!("Kubernetes error: #{e.error_code}") rescue StandardError => e log_error(e) - app.make_update_errored!("Can't start update process.") + app.make_errored!('Failed to update.') end end end diff --git a/app/services/clusters/applications/upgrade_service.rb b/app/services/clusters/applications/upgrade_service.rb index c34391bc8ad..813a9c4d071 100644 --- a/app/services/clusters/applications/upgrade_service.rb +++ b/app/services/clusters/applications/upgrade_service.rb @@ -6,24 +6,28 @@ module Clusters def execute return unless app.scheduled? - begin - app.make_updating! + app.make_updating! - log_event(:begin_upgrade) - # install_command works with upgrades too - # as it basically does `helm upgrade --install` - helm_api.update(install_command) + upgrade + end + + private + + def upgrade + # install_command works with upgrades too + # as it basically does `helm upgrade --install` + log_event(:begin_upgrade) + helm_api.update(install_command) - log_event(:schedule_wait_for_upgrade) - ClusterWaitForAppInstallationWorker.perform_in( - ClusterWaitForAppInstallationWorker::INTERVAL, app.name, app.id) - rescue Kubeclient::HttpError => e - log_error(e) - app.make_update_errored!("Kubernetes error: #{e.error_code}") - rescue StandardError => e - log_error(e) - app.make_update_errored!("Can't start upgrade process.") - end + log_event(:schedule_wait_for_upgrade) + ClusterWaitForAppInstallationWorker.perform_in( + ClusterWaitForAppInstallationWorker::INTERVAL, app.name, app.id) + rescue Kubeclient::HttpError => e + log_error(e) + app.make_errored!("Kubernetes error: #{e.error_code}") + rescue StandardError => e + log_error(e) + app.make_errored!('Failed to upgrade.') end end end diff --git a/app/services/users/activity_service.rb b/app/services/users/activity_service.rb index e50840a9158..33444c2a7dc 100644 --- a/app/services/users/activity_service.rb +++ b/app/services/users/activity_service.rb @@ -30,7 +30,7 @@ module Users return if @user.last_activity_on == today - lease = Gitlab::ExclusiveLease.new("acitvity_service:#{@user.id}", + lease = Gitlab::ExclusiveLease.new("activity_service:#{@user.id}", timeout: LEASE_TIMEOUT) return unless lease.try_obtain diff --git a/app/views/projects/pipeline_schedules/_form.html.haml b/app/views/projects/pipeline_schedules/_form.html.haml index 1121cf06b5c..396e5da87bc 100644 --- a/app/views/projects/pipeline_schedules/_form.html.haml +++ b/app/views/projects/pipeline_schedules/_form.html.haml @@ -1,4 +1,4 @@ -= form_for [@project.namespace.becomes(Namespace), @project, @schedule], as: :schedule, html: { id: "new-pipeline-schedule-form", class: "js-pipeline-schedule-form" } do |f| += form_for [@project.namespace.becomes(Namespace), @project, @schedule], as: :schedule, html: { id: "new-pipeline-schedule-form", class: "js-pipeline-schedule-form pipeline-schedule-form" } do |f| = form_errors(@schedule) .form-group.row .col-md-9 @@ -11,12 +11,12 @@ .form-group.row .col-md-9 = f.label :cron_timezone, _('Cron Timezone'), class: 'label-bold' - = dropdown_tag(_("Select a timezone"), options: { toggle_class: 'btn js-timezone-dropdown', title: _("Select a timezone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } ) + = dropdown_tag(_("Select a timezone"), options: { toggle_class: 'btn js-timezone-dropdown w-100', dropdown_class: 'w-100', title: _("Select a timezone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } ) = f.text_field :cron_timezone, value: @schedule.cron_timezone, id: 'schedule_cron_timezone', class: 'hidden', name: 'schedule[cron_timezone]', required: true .form-group.row .col-md-9 = f.label :ref, _('Target Branch'), class: 'label-bold' - = dropdown_tag(_("Select target branch"), options: { toggle_class: 'btn js-target-branch-dropdown', dropdown_class: 'git-revision-dropdown', title: _("Select target branch"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: @project.repository.branch_names, default_branch: @project.default_branch } } ) + = dropdown_tag(_("Select target branch"), options: { toggle_class: 'btn js-target-branch-dropdown w-100', dropdown_class: 'git-revision-dropdown w-100', title: _("Select target branch"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: @project.repository.branch_names, default_branch: @project.default_branch } } ) = f.text_field :ref, value: @schedule.ref, id: 'schedule_ref', class: 'hidden', name: 'schedule[ref]', required: true .form-group.row.js-ci-variable-list-section .col-md-9 diff --git a/changelogs/unreleased/59921-pipeline-schedule.yml b/changelogs/unreleased/59921-pipeline-schedule.yml new file mode 100644 index 00000000000..4227a047913 --- /dev/null +++ b/changelogs/unreleased/59921-pipeline-schedule.yml @@ -0,0 +1,5 @@ +--- +title: Replaces CSS with BS4 utility class for pipeline schedules +merge_request: +author: +type: other diff --git a/locale/gitlab.pot b/locale/gitlab.pot index cfd630ae8e2..4f401acccf9 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -132,6 +132,12 @@ msgstr "" msgid "%{label_for_message} unavailable" msgstr "" +msgid "%{level_name} is not allowed in a %{group_level_name} group." +msgstr "" + +msgid "%{level_name} is not allowed since the fork source project has lower visibility." +msgstr "" + msgid "%{level_name} visibility has been restricted by the administrator." msgstr "" @@ -203,6 +209,12 @@ msgstr "" msgid "%{user_name} profile page" msgstr "" +msgid "'%{level}' is not a valid visibility level" +msgstr "" + +msgid "'%{source}' is not a import source" +msgstr "" + msgid "(external source)" msgstr "" @@ -978,6 +990,18 @@ msgstr "" msgid "Artifacts" msgstr "" +msgid "AsanaService|%{user} pushed to branch %{branch} of %{project_name} ( %{commit_url} ):" +msgstr "" + +msgid "AsanaService|Asana - Teamwork without email" +msgstr "" + +msgid "AsanaService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches." +msgstr "" + +msgid "AsanaService|User Personal Access Token. User must have access to task, all comments will be attributed to this user." +msgstr "" + msgid "Ask your group maintainer to set up a group Runner." msgstr "" @@ -1221,6 +1245,24 @@ msgstr "" msgid "Badges|e.g. %{exampleUrl}" msgstr "" +msgid "BambooService|A continuous integration and build server" +msgstr "" + +msgid "BambooService|A user with API access, if applicable" +msgstr "" + +msgid "BambooService|Atlassian Bamboo CI" +msgstr "" + +msgid "BambooService|Bamboo build plan key like KEY" +msgstr "" + +msgid "BambooService|Bamboo root URL like https://bamboo.example.com" +msgstr "" + +msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo." +msgstr "" + msgid "Be careful. Changing the project's namespace can have unintended side effects." msgstr "" @@ -1515,6 +1557,9 @@ msgstr "" msgid "Cannot modify managed Kubernetes cluster" msgstr "" +msgid "Cannot refer to a group milestone by an internal id!" +msgstr "" + msgid "Cannot render the image. Maximum character count (%{charLimit}) has been exceeded." msgstr "" @@ -2600,6 +2645,9 @@ msgstr "" msgid "Could not authorize chat nickname. Try again!" msgstr "" +msgid "Could not change HEAD: branch '%{branch}' does not exist" +msgstr "" + msgid "Could not connect to FogBugz, check your URL" msgstr "" @@ -3109,6 +3157,12 @@ msgstr "" msgid "Discard draft" msgstr "" +msgid "DiscordService|Discord Notifications" +msgstr "" + +msgid "DiscordService|Receive event notifications in Discord" +msgstr "" + msgid "Discover projects, groups and snippets. Share your projects with others" msgstr "" @@ -3235,6 +3289,9 @@ msgstr "" msgid "Email patch" msgstr "" +msgid "Email the pipelines status to a list of recipients." +msgstr "" + msgid "EmailError|It appears that the email is blank. Make sure your reply is at the top of the email, we can't process inline replies." msgstr "" @@ -3262,6 +3319,30 @@ msgstr "" msgid "Emails" msgstr "" +msgid "Emails separated by comma" +msgstr "" + +msgid "EmailsOnPushService|Disable code diffs" +msgstr "" + +msgid "EmailsOnPushService|Don't include possibly sensitive code diffs in notification body." +msgstr "" + +msgid "EmailsOnPushService|Email the commits and diff of each push to a list of recipients." +msgstr "" + +msgid "EmailsOnPushService|Emails on push" +msgstr "" + +msgid "EmailsOnPushService|Emails separated by whitespace" +msgstr "" + +msgid "EmailsOnPushService|Send from committer" +msgstr "" + +msgid "EmailsOnPushService|Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. %{domains})." +msgstr "" + msgid "Embed" msgstr "" @@ -3751,6 +3832,15 @@ msgstr "" msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used." msgstr "" +msgid "ExternalWikiService|External Wiki" +msgstr "" + +msgid "ExternalWikiService|Replaces the link to the internal wiki with a link to an external wiki." +msgstr "" + +msgid "ExternalWikiService|The URL of the external Wiki" +msgstr "" + msgid "Facebook" msgstr "" @@ -3760,12 +3850,18 @@ msgstr "" msgid "Failed Jobs" msgstr "" +msgid "Failed create wiki" +msgstr "" + msgid "Failed to change the owner" msgstr "" msgid "Failed to check related branches." msgstr "" +msgid "Failed to create repository via gitlab-shell" +msgstr "" + msgid "Failed to create resources" msgstr "" @@ -3921,6 +4017,12 @@ msgstr "" msgid "FirstPushedBy|pushed by" msgstr "" +msgid "FlowdockService|Flowdock Git source token" +msgstr "" + +msgid "FlowdockService|Flowdock is a collaboration web app for technical teams." +msgstr "" + msgid "FogBugz Email" msgstr "" @@ -4607,6 +4709,9 @@ msgstr "" msgid "Incompatible Project" msgstr "" +msgid "Incompatible options set!" +msgstr "" + msgid "Indicates whether this runner can pick jobs without tags" msgstr "" @@ -4682,6 +4787,9 @@ msgstr "" msgid "Invalid Login or password" msgstr "" +msgid "Invalid feature" +msgstr "" + msgid "Invalid file." msgstr "" @@ -4691,6 +4799,9 @@ msgstr "" msgid "Invalid pin code" msgstr "" +msgid "Invalid repository path" +msgstr "" + msgid "Invalid two-factor code." msgstr "" @@ -4751,6 +4862,48 @@ msgstr "" msgid "January" msgstr "" +msgid "JiraService|Events for %{noteable_model_name} are disabled." +msgstr "" + +msgid "JiraService|If different from Web URL" +msgstr "" + +msgid "JiraService|JIRA API URL" +msgstr "" + +msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit." +msgstr "" + +msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request." +msgstr "" + +msgid "JiraService|Jira issue tracker" +msgstr "" + +msgid "JiraService|Password or API token" +msgstr "" + +msgid "JiraService|Transition ID(s)" +msgstr "" + +msgid "JiraService|Use , or ; to separate multiple transition IDs" +msgstr "" + +msgid "JiraService|Use a password for server version and an API token for cloud version" +msgstr "" + +msgid "JiraService|Use a username for server version and an email for cloud version" +msgstr "" + +msgid "JiraService|Username or Email" +msgstr "" + +msgid "JiraService|Web URL" +msgstr "" + +msgid "JiraService|transition ids can have only numbers which can be split with , or ;" +msgstr "" + msgid "Job" msgstr "" @@ -5187,6 +5340,9 @@ msgstr "" msgid "Maximum job timeout" msgstr "" +msgid "Maximum job timeout has a value which could not be accepted" +msgstr "" + msgid "Maximum push size (MB)" msgstr "" @@ -6133,6 +6289,9 @@ msgstr "" msgid "Pipelines charts" msgstr "" +msgid "Pipelines emails" +msgstr "" + msgid "Pipelines for last month" msgstr "" @@ -6256,6 +6415,15 @@ msgstr "" msgid "Pipeline|with stages" msgstr "" +msgid "PivotalTrackerService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches." +msgstr "" + +msgid "PivotalTrackerService|Pivotal Tracker API token." +msgstr "" + +msgid "PivotalTrackerService|Project Management Software (Source Commits Endpoint)" +msgstr "" + msgid "Plain diff" msgstr "" @@ -6667,6 +6835,9 @@ msgstr "" msgid "Project avatar" msgstr "" +msgid "Project cannot be shared with the group it is in or one of its ancestors." +msgstr "" + msgid "Project configuration, including services" msgstr "" @@ -6928,6 +7099,45 @@ msgstr "" msgid "Push to create a project" msgstr "" +msgid "PushoverService|%{user_name} deleted branch \"%{ref}\"." +msgstr "" + +msgid "PushoverService|%{user_name} push to branch \"%{ref}\"." +msgstr "" + +msgid "PushoverService|%{user_name} pushed new branch \"%{ref}\"." +msgstr "" + +msgid "PushoverService|High Priority" +msgstr "" + +msgid "PushoverService|Leave blank for all active devices" +msgstr "" + +msgid "PushoverService|Low Priority" +msgstr "" + +msgid "PushoverService|Lowest Priority" +msgstr "" + +msgid "PushoverService|Normal Priority" +msgstr "" + +msgid "PushoverService|Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop." +msgstr "" + +msgid "PushoverService|See project %{project_full_name}" +msgstr "" + +msgid "PushoverService|Total commits count: %{total_commits_count}" +msgstr "" + +msgid "PushoverService|Your application key" +msgstr "" + +msgid "PushoverService|Your user key" +msgstr "" + msgid "Quick actions can be used in the issues description and comment boxes." msgstr "" @@ -7014,6 +7224,9 @@ msgstr "" msgid "Remind later" msgstr "" +msgid "Remote object has no absolute path." +msgstr "" + msgid "Remove" msgstr "" @@ -8427,6 +8640,9 @@ msgstr "" msgid "The name %{entryName} is already taken in this directory." msgstr "" +msgid "The number of times an upload record could not find its file" +msgstr "" + msgid "The passphrase required to decrypt the private key. This is optional and the value is encrypted at rest." msgstr "" @@ -8454,12 +8670,18 @@ msgstr "" msgid "The project can be accessed without any authentication." msgstr "" +msgid "The project is still being deleted. Please try again later." +msgstr "" + msgid "The project was successfully forked." msgstr "" msgid "The project was successfully imported." msgstr "" +msgid "The remote mirror took to long to complete." +msgstr "" + msgid "The remote repository is being updated..." msgstr "" @@ -8559,6 +8781,9 @@ msgstr "" msgid "There are no unstaged changes" msgstr "" +msgid "There is already a repository with that name on disk" +msgstr "" + msgid "There was an error loading users activity calendar." msgstr "" @@ -8655,6 +8880,9 @@ msgstr "" msgid "This group does not provide any group Runners yet." msgstr "" +msgid "This is a \"Ghost User\", created to hold all issues authored by users that have since been deleted. This user cannot be removed." +msgstr "" + msgid "This is a confidential issue." msgstr "" @@ -9196,6 +9424,12 @@ msgstr "" msgid "Unfortunately, your email message to GitLab could not be processed." msgstr "" +msgid "Unknown encryption strategy: %{encrypted_strategy}!" +msgstr "" + +msgid "Unknown format" +msgstr "" + msgid "Unlock" msgstr "" @@ -9292,6 +9526,9 @@ msgstr "" msgid "Upload file" msgstr "" +msgid "Upload file does not exist" +msgstr "" + msgid "Upload object map" msgstr "" @@ -9457,6 +9694,9 @@ msgstr "" msgid "Users were successfully added." msgstr "" +msgid "Using required encryption strategy when encrypted field is missing!" +msgstr "" + msgid "Validate" msgstr "" @@ -10038,6 +10278,9 @@ msgstr "" msgid "Your Todos" msgstr "" +msgid "Your U2F device did not send a valid JSON response." +msgstr "" + msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left." msgstr "" @@ -10119,6 +10362,12 @@ msgstr "" msgid "allowed to fail" msgstr "" +msgid "already being used for another group or project milestone." +msgstr "" + +msgid "already shared with this group" +msgstr "" + msgid "among other things" msgstr "" @@ -10131,6 +10380,15 @@ msgstr "" msgid "branch name" msgstr "" +msgid "cannot be changed if a personal project has container registry tags." +msgstr "" + +msgid "cannot be enabled unless all domains have TLS certificates" +msgstr "" + +msgid "cannot include leading slash or directory traversal." +msgstr "" + msgid "commented on %{link_to_project}" msgstr "" @@ -10174,9 +10432,15 @@ msgstr[1] "" msgid "done" msgstr "" +msgid "element is not a hierarchy" +msgstr "" + msgid "enabled" msgstr "" +msgid "encrypted: needs to be a :required, :optional or :migrating!" +msgstr "" + msgid "error" msgstr "" @@ -10210,6 +10474,9 @@ msgstr "" msgid "group" msgstr "" +msgid "has already been taken" +msgstr "" + msgid "here" msgstr "" @@ -10237,6 +10504,9 @@ msgstr "" msgid "is not a valid X509 certificate." msgstr "" +msgid "is not an email you own" +msgstr "" + msgid "issue boards" msgstr "" @@ -10269,6 +10539,9 @@ msgid_plural "merge requests" msgstr[0] "" msgstr[1] "" +msgid "milestone should belong either to a project or a group." +msgstr "" + msgid "missing" msgstr "" @@ -10476,9 +10749,15 @@ msgstr "" msgid "mrWidget|to be merged automatically when the pipeline succeeds" msgstr "" +msgid "must be greater than start date" +msgstr "" + msgid "n/a" msgstr "" +msgid "needs to be beetween 10 minutes and 1 month" +msgstr "" + msgid "new merge request" msgstr "" @@ -10566,6 +10845,9 @@ msgstr "" msgid "source diff" msgstr "" +msgid "specified top is not part of the tree" +msgstr "" + msgid "spendCommand|%{slash_command} will update the sum of the time spent." msgstr "" diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock index c9b0db6a272..9d3d42fb6ae 100644 --- a/qa/Gemfile.lock +++ b/qa/Gemfile.lock @@ -49,7 +49,7 @@ GEM mini_portile2 (2.4.0) minitest (5.11.1) netrc (0.11.0) - nokogiri (1.10.1) + nokogiri (1.10.2) mini_portile2 (~> 2.4.0) pry (0.11.3) coderay (~> 1.1.0) diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index 25ed3bdc88e..ce780789f5a 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -73,22 +73,26 @@ describe 'Admin::Hooks' do end describe 'Remove existing hook', :js do + let(:hook_url) { generate(:url) } + before do - create(:system_hook) + create(:system_hook, url: hook_url) end context 'removes existing hook' do it 'from hooks list page' do visit admin_hooks_path - expect { accept_confirm { find(:link, 'Remove').send_keys(:return) } }.to change(SystemHook, :count).by(-1) + accept_confirm { click_link 'Remove' } + expect(page).not_to have_content(hook_url) end it 'from hook edit page' do visit admin_hooks_path click_link 'Edit' - expect { accept_confirm { find(:link, 'Remove').send_keys(:return) } }.to change(SystemHook, :count).by(-1) + accept_confirm { click_link 'Remove' } + expect(page).not_to have_content(hook_url) end end end diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb index 50ba67f0ffc..f26941ab567 100644 --- a/spec/features/projects/members/user_requests_access_spec.rb +++ b/spec/features/projects/members/user_requests_access_spec.rb @@ -62,8 +62,9 @@ describe 'Projects > Members > User requests access', :js do accept_confirm { click_link 'Withdraw Access Request' } - expect(project.requesters.exists?(user_id: user)).to be_falsey expect(page).to have_content 'Your access request to the project has been withdrawn.' + expect(page).not_to have_content 'Withdraw Access Request' + expect(page).to have_content 'Request Access' end def open_project_settings_menu diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb index ae9b65d1a39..ea02f36d9d0 100644 --- a/spec/features/u2f_spec.rb +++ b/spec/features/u2f_spec.rb @@ -246,26 +246,6 @@ describe 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do end end end - - describe "when two-factor authentication is disabled" do - let(:user) { create(:user) } - - before do - user = gitlab_sign_in(:user) - user.update_attribute(:otp_required_for_login, true) - visit profile_account_path - manage_two_factor_authentication - expect(page).to have_content("Your U2F device needs to be set up.") - register_u2f_device - end - - it "deletes u2f registrations" do - visit profile_two_factor_auth_path - expect do - accept_confirm { click_on "Disable" } - end.to change { U2fRegistration.count }.by(-1) - end - end end describe 'fallback code authentication' do diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index cacdb0e0595..d5c85c11195 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -22,6 +22,7 @@ describe WikiPage do create_page('dir_1/dir_1_1/page_3', 'content') create_page('page_1', 'content') create_page('dir_1/page_2', 'content') + create_page('dir_2', 'page with dir name') create_page('dir_2/page_5', 'content') create_page('page_6', 'content') create_page('dir_2/page_4', 'content') @@ -29,6 +30,7 @@ describe WikiPage do let(:page_1) { wiki.find_page('page_1') } let(:page_6) { wiki.find_page('page_6') } + let(:page_dir_2) { wiki.find_page('dir_2') } let(:dir_1) do WikiDirectory.new('dir_1', [wiki.find_page('dir_1/page_2')]) @@ -44,7 +46,7 @@ describe WikiPage do context 'sort by title' do let(:grouped_entries) { described_class.group_by_directory(wiki.pages) } - let(:expected_grouped_entries) { [dir_1_1, dir_1, dir_2, page_1, page_6] } + let(:expected_grouped_entries) { [dir_1_1, dir_1, page_dir_2, dir_2, page_1, page_6] } it 'returns an array with pages and directories' do grouped_entries.each_with_index do |page_or_dir, i| @@ -59,7 +61,7 @@ describe WikiPage do context 'sort by created_at' do let(:grouped_entries) { described_class.group_by_directory(wiki.pages(sort: 'created_at')) } - let(:expected_grouped_entries) { [dir_1_1, page_1, dir_1, dir_2, page_6] } + let(:expected_grouped_entries) { [dir_1_1, page_1, dir_1, page_dir_2, dir_2, page_6] } it 'returns an array with pages and directories' do grouped_entries.each_with_index do |page_or_dir, i| @@ -73,7 +75,7 @@ describe WikiPage do end it 'returns an array with retained order with directories at the top' do - expected_order = ['dir_1/dir_1_1/page_3', 'dir_1/page_2', 'dir_2/page_4', 'dir_2/page_5', 'page_1', 'page_6'] + expected_order = ['dir_1/dir_1_1/page_3', 'dir_1/page_2', 'dir_2', 'dir_2/page_4', 'dir_2/page_5', 'page_1', 'page_6'] grouped_entries = described_class.group_by_directory(wiki.pages) diff --git a/spec/services/clusters/applications/install_service_spec.rb b/spec/services/clusters/applications/install_service_spec.rb index db0c33a95b2..14739ff9e7c 100644 --- a/spec/services/clusters/applications/install_service_spec.rb +++ b/spec/services/clusters/applications/install_service_spec.rb @@ -58,7 +58,7 @@ describe Clusters::Applications::InstallService do let(:error) { StandardError.new('something bad happened') } before do - expect(application).to receive(:make_installing!).once.and_raise(error) + expect(helm_client).to receive(:install).with(install_command).and_raise(error) end include_examples 'logs kubernetes errors' do @@ -68,12 +68,10 @@ describe Clusters::Applications::InstallService do end it 'make the application errored' do - expect(helm_client).not_to receive(:install) - service.execute expect(application).to be_errored - expect(application.status_reason).to eq("Can't start installation process.") + expect(application.status_reason).to eq('Failed to install.') end end end diff --git a/spec/services/clusters/applications/patch_service_spec.rb b/spec/services/clusters/applications/patch_service_spec.rb index 10b1379a127..3ebe0540837 100644 --- a/spec/services/clusters/applications/patch_service_spec.rb +++ b/spec/services/clusters/applications/patch_service_spec.rb @@ -66,16 +66,14 @@ describe Clusters::Applications::PatchService do end before do - expect(application).to receive(:make_updating!).once.and_raise(error) + expect(helm_client).to receive(:update).with(update_command).and_raise(error) end it 'make the application errored' do - expect(helm_client).not_to receive(:update) - service.execute expect(application).to be_update_errored - expect(application.status_reason).to eq("Can't start update process.") + expect(application.status_reason).to eq('Failed to update.') end end end diff --git a/spec/services/clusters/applications/upgrade_service_spec.rb b/spec/services/clusters/applications/upgrade_service_spec.rb index dd2e6e94e4f..a80b1d9127c 100644 --- a/spec/services/clusters/applications/upgrade_service_spec.rb +++ b/spec/services/clusters/applications/upgrade_service_spec.rb @@ -60,7 +60,7 @@ describe Clusters::Applications::UpgradeService do let(:error) { StandardError.new('something bad happened') } before do - expect(application).to receive(:make_updating!).once.and_raise(error) + expect(helm_client).to receive(:update).with(install_command).and_raise(error) end include_examples 'logs kubernetes errors' do @@ -70,12 +70,10 @@ describe Clusters::Applications::UpgradeService do end it 'make the application errored' do - expect(helm_client).not_to receive(:update) - service.execute expect(application).to be_update_errored - expect(application.status_reason).to eq("Can't start upgrade process.") + expect(application.status_reason).to eq('Failed to upgrade.') end end end diff --git a/spec/services/users/activity_service_spec.rb b/spec/services/users/activity_service_spec.rb index 3c0a4ac8e18..7b11d9e06e9 100644 --- a/spec/services/users/activity_service_spec.rb +++ b/spec/services/users/activity_service_spec.rb @@ -76,7 +76,7 @@ describe Users::ActivityService do let(:last_activity_on) { nil } it 'does not update last_activity_on' do - stub_exclusive_lease_taken("acitvity_service:#{user.id}", timeout: 1.minute.to_i) + stub_exclusive_lease_taken("activity_service:#{user.id}", timeout: 1.minute.to_i) expect { subject.execute }.not_to change(user, :last_activity_on) end diff --git a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb index 75ad948e42c..d87e5fcaa88 100644 --- a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb +++ b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb @@ -19,7 +19,7 @@ RSpec.shared_examples 'Maintainer manages access requests' do expect_visible_access_request(entity, user) - accept_confirm { click_on 'Grant access' } + click_on 'Grant access' expect_no_visible_access_request(entity, user) @@ -40,13 +40,11 @@ RSpec.shared_examples 'Maintainer manages access requests' do end def expect_visible_access_request(entity, user) - expect(entity.requesters.exists?(user_id: user)).to be_truthy expect(page).to have_content "Users requesting access to #{entity.name} 1" expect(page).to have_content user.name end def expect_no_visible_access_request(entity, user) - expect(entity.requesters.exists?(user_id: user)).to be_falsy expect(page).not_to have_content "Users requesting access to #{entity.name}" end end |