diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index 61bbf13aa53088b58f0d1f633f1fccc08dc1fe12..d2110483c1c030528d8c28e318f688b9940ed1ca 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -2,7 +2,6 @@ import { escape } from 'lodash'; import { mapActions, mapGetters } from 'vuex'; import { GlDeprecatedButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui'; -import { polyfillSticky } from '~/lib/utils/sticky'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import Icon from '~/vue_shared/components/icon.vue'; import FileIcon from '~/vue_shared/components/file_icon.vue'; @@ -124,9 +123,6 @@ export default { return s__('MRDiff|Show full file'); }, }, - mounted() { - polyfillSticky(this.$refs.header); - }, methods: { ...mapActions('diffs', [ 'toggleFileDiscussions', diff --git a/app/assets/javascripts/editor/editor_lite.js b/app/assets/javascripts/editor/editor_lite.js index 6db24a1b7efecf3649b7f2ceb304bf4e372bf4ad..551ffbabaef131a8d53608350bf701888e9d401e 100644 --- a/app/assets/javascripts/editor/editor_lite.js +++ b/app/assets/javascripts/editor/editor_lite.js @@ -88,4 +88,9 @@ export default class Editor { updateOptions(options = {}) { this.instance.updateOptions(options); } + + use(exts = []) { + const extensions = Array.isArray(exts) ? exts : [exts]; + Object.assign(this, ...extensions); + } } diff --git a/app/assets/javascripts/snippets/fragments/project.fragment.graphql b/app/assets/javascripts/snippets/fragments/project.fragment.graphql index 7d65789c67b997423db99fdd3c0797f836e764bd..64bb2315c1b6810c74dc45204b7c07b41ea1abfd 100644 --- a/app/assets/javascripts/snippets/fragments/project.fragment.graphql +++ b/app/assets/javascripts/snippets/fragments/project.fragment.graphql @@ -1,6 +1,6 @@ -fragment Project on Snippet { +fragment SnippetProject on Snippet { project { fullPath webUrl } -} \ No newline at end of file +} diff --git a/app/assets/javascripts/snippets/queries/snippet.query.graphql b/app/assets/javascripts/snippets/queries/snippet.query.graphql index c58a5168ba37fa45dd0ac977100d55e9a42d1f8a..b23ab862439824785b17850df1208967ce53419f 100644 --- a/app/assets/javascripts/snippets/queries/snippet.query.graphql +++ b/app/assets/javascripts/snippets/queries/snippet.query.graphql @@ -7,7 +7,7 @@ query GetSnippetQuery($ids: [ID!]) { edges { node { ...SnippetBase - ...Project + ...SnippetProject author { ...Author } diff --git a/app/controllers/concerns/service_params.rb b/app/controllers/concerns/service_params.rb index e78fa8f8250d1cab06c3a5f5afcf94e67f90bc02..a3e986572ef43bd7b3c6b6102fc06bfcfc2d6a40 100644 --- a/app/controllers/concerns/service_params.rb +++ b/app/controllers/concerns/service_params.rb @@ -23,7 +23,6 @@ module ServiceParams :comment_detail, :confidential_issues_events, :default_irc_uri, - :description, :device, :disable_diffs, :drone_url, @@ -61,7 +60,6 @@ module ServiceParams :sound, :subdomain, :teamcity_url, - :title, :token, :type, :url, diff --git a/app/controllers/concerns/snippets/blobs_actions.rb b/app/controllers/concerns/snippets/blobs_actions.rb new file mode 100644 index 0000000000000000000000000000000000000000..db56ce8f193f5eae7ddbbf4a20fa86ff13de38c7 --- /dev/null +++ b/app/controllers/concerns/snippets/blobs_actions.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Snippets::BlobsActions + extend ActiveSupport::Concern + + include Gitlab::Utils::StrongMemoize + include ExtractsRef + include Snippets::SendBlob + + included do + before_action :authorize_read_snippet!, only: [:raw] + before_action :ensure_repository + before_action :ensure_blob + end + + def raw + send_snippet_blob(snippet, blob) + end + + private + + def repository_container + snippet + end + + # rubocop:disable Gitlab/ModuleWithInstanceVariables + def blob + strong_memoize(:blob) do + assign_ref_vars + + next unless @commit + + @repo.blob_at(@commit.id, @path) + end + end + # rubocop:enable Gitlab/ModuleWithInstanceVariables + + def ensure_blob + render_404 unless blob + end + + def ensure_repository + unless snippet.repo_exists? + Gitlab::AppLogger.error(message: "Snippet raw blob attempt with no repo", snippet: snippet.id) + + respond_422 + end + end + + def snippet_id + params[:snippet_id] + end +end diff --git a/app/controllers/concerns/snippets/send_blob.rb b/app/controllers/concerns/snippets/send_blob.rb new file mode 100644 index 0000000000000000000000000000000000000000..4f432430aaa532ebe8b5ca9ea9e43dc6156e747f --- /dev/null +++ b/app/controllers/concerns/snippets/send_blob.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Snippets::SendBlob + include SendsBlob + + def send_snippet_blob(snippet, blob) + workhorse_set_content_type! + + send_blob( + snippet.repository, + blob, + inline: content_disposition == 'inline', + allow_caching: snippet.public? + ) + end + + private + + def content_disposition + @disposition ||= params[:inline] == 'false' ? 'attachment' : 'inline' + end +end diff --git a/app/controllers/concerns/snippets_actions.rb b/app/controllers/concerns/snippets_actions.rb index 51fc12398d964b6755831646a9111f869888bcc4..3b8f972291340c970421b33b39e6907c3de059eb 100644 --- a/app/controllers/concerns/snippets_actions.rb +++ b/app/controllers/concerns/snippets_actions.rb @@ -2,11 +2,12 @@ module SnippetsActions extend ActiveSupport::Concern - include SendsBlob + include RendersNotes include RendersBlob include PaginatedCollection include Gitlab::NoteableMetadata + include Snippets::SendBlob included do skip_before_action :verify_authenticity_token, @@ -25,6 +26,10 @@ module SnippetsActions render 'edit' end + # This endpoint is being replaced by Snippets::BlobController#raw + # Support for old raw links will be maintainted via this action but + # it will only return the first blob found, + # see: https://gitlab.com/gitlab-org/gitlab/-/issues/217775 def raw workhorse_set_content_type! @@ -39,12 +44,7 @@ module SnippetsActions filename: Snippet.sanitized_file_name(blob.name) ) else - send_blob( - snippet.repository, - blob, - inline: content_disposition == 'inline', - allow_caching: snippet.public? - ) + send_snippet_blob(snippet, blob) end end @@ -106,10 +106,6 @@ module SnippetsActions private - def content_disposition - @disposition ||= params[:inline] == 'false' ? 'attachment' : 'inline' - end - # rubocop:disable Gitlab/ModuleWithInstanceVariables def blob return unless snippet diff --git a/app/controllers/projects/snippets/blobs_controller.rb b/app/controllers/projects/snippets/blobs_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..148fc7c96f8afd994d8316b9581a8f9ae2d58f19 --- /dev/null +++ b/app/controllers/projects/snippets/blobs_controller.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class Projects::Snippets::BlobsController < Projects::Snippets::ApplicationController + include Snippets::BlobsActions +end diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb index 5ee6abef80421762df7ba271a60e34e706d7a7f0..1bc63fce5fcf426d0af561b630b72a9c29c264e1 100644 --- a/app/controllers/projects/snippets_controller.rb +++ b/app/controllers/projects/snippets_controller.rb @@ -15,7 +15,7 @@ class Projects::SnippetsController < Projects::Snippets::ApplicationController before_action :authorize_admin_snippet!, only: [:destroy] def index - @snippet_counts = Snippets::CountService + @snippet_counts = ::Snippets::CountService .new(current_user, project: @project) .execute @@ -35,7 +35,7 @@ class Projects::SnippetsController < Projects::Snippets::ApplicationController def create create_params = snippet_params.merge(spammable_params) - service_response = Snippets::CreateService.new(project, current_user, create_params).execute + service_response = ::Snippets::CreateService.new(project, current_user, create_params).execute @snippet = service_response.payload[:snippet] handle_repository_error(:new) diff --git a/app/controllers/snippets/blobs_controller.rb b/app/controllers/snippets/blobs_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..d7c4bbcf8f2e058badaeb838008e7f3ddc325e1a --- /dev/null +++ b/app/controllers/snippets/blobs_controller.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class Snippets::BlobsController < Snippets::ApplicationController + include Snippets::BlobsActions + + skip_before_action :authenticate_user!, only: [:raw] +end diff --git a/app/graphql/resolvers/projects/jira_projects_resolver.rb b/app/graphql/resolvers/projects/jira_projects_resolver.rb index a8c3768df41b6b1ac2698685d2afd00447687ad2..2b5d04ef39e764a68a1d3998326d62f6d7741669 100644 --- a/app/graphql/resolvers/projects/jira_projects_resolver.rb +++ b/app/graphql/resolvers/projects/jira_projects_resolver.rb @@ -13,11 +13,10 @@ module Resolvers def resolve(name: nil, **args) authorize!(project) - response, start_cursor, end_cursor = jira_projects(name: name, **compute_pagination_params(args)) - end_cursor = nil if !!response.payload[:is_last] + response = jira_projects(name: name) if response.success? - Gitlab::Graphql::ExternallyPaginatedArray.new(start_cursor, end_cursor, *response.payload[:projects]) + response.payload[:projects] else raise Gitlab::Graphql::Errors::BaseError, response.message end @@ -35,41 +34,10 @@ module Resolvers jira_service&.project end - def compute_pagination_params(params) - after_cursor = Base64.decode64(params[:after].to_s) - before_cursor = Base64.decode64(params[:before].to_s) + def jira_projects(name:) + args = { query: name }.compact - # differentiate between 0 cursor and nil or invalid cursor that decodes into zero. - after_index = after_cursor.to_i == 0 && after_cursor != "0" ? nil : after_cursor.to_i - before_index = before_cursor.to_i == 0 && before_cursor != "0" ? nil : before_cursor.to_i - - if after_index.present? && before_index.present? - if after_index >= before_index - { start_at: 0, limit: 0 } - else - { start_at: after_index + 1, limit: before_index - after_index - 1 } - end - elsif after_index.present? - { start_at: after_index + 1, limit: nil } - elsif before_index.present? - { start_at: 0, limit: before_index - 1 } - else - { start_at: 0, limit: nil } - end - end - - def jira_projects(name:, start_at:, limit:) - args = { query: name, start_at: start_at, limit: limit }.compact - - response = Jira::Requests::Projects.new(project.jira_service, args).execute - - return [response, nil, nil] if response.error? - - projects = response.payload[:projects] - start_cursor = start_at == 0 ? nil : Base64.encode64((start_at - 1).to_s) - end_cursor = Base64.encode64((start_at + projects.size - 1).to_s) - - [response, start_cursor, end_cursor] + return Jira::Requests::Projects.new(project.jira_service, args).execute end end end diff --git a/app/graphql/types/projects/services/jira_service_type.rb b/app/graphql/types/projects/services/jira_service_type.rb index e81963f752d3d2a0f45be078f4c9ccfc670e1a87..8bf85a14cbfdf6dddf2e6e78aa8f899e1b5198e1 100644 --- a/app/graphql/types/projects/services/jira_service_type.rb +++ b/app/graphql/types/projects/services/jira_service_type.rb @@ -15,7 +15,7 @@ module Types null: true, connection: false, extensions: [Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension], - description: 'List of Jira projects fetched through Jira REST API', + description: 'List of all Jira projects fetched through Jira REST API', resolver: Resolvers::Projects::JiraProjectsResolver end end diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb index c756a9b546ad5c71c9d3ac1331db59554bdf5ff0..4094bdb26dccd30f950182423cbadfbe9ee1d18c 100644 --- a/app/models/ci/build_metadata.rb +++ b/app/models/ci/build_metadata.rb @@ -19,6 +19,7 @@ module Ci before_create :set_build_project validates :build, presence: true + validates :secrets, json_schema: { filename: 'build_metadata_secrets' } serialize :config_options, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize serialize :config_variables, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize @@ -83,5 +84,3 @@ module Ci end end end - -Ci::BuildMetadata.prepend_if_ee('EE::Ci::BuildMetadata') diff --git a/app/models/project_services/bugzilla_service.rb b/app/models/project_services/bugzilla_service.rb index 0a498fde95a46e1a25fd36e9603f19784499bcdf..4332db3e9613f1779c940752bb0c6091ad6e75f0 100644 --- a/app/models/project_services/bugzilla_service.rb +++ b/app/models/project_services/bugzilla_service.rb @@ -3,11 +3,11 @@ class BugzillaService < IssueTrackerService validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? - def default_title + def title 'Bugzilla' end - def default_description + def description s_('IssueTracker|Bugzilla issue tracker') end diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb index dbc42b1b86d6f919e4baf431ac014a66a4a006cb..fc58ba27c3d3ddcc1754a4d2350c50c5b908ea0b 100644 --- a/app/models/project_services/custom_issue_tracker_service.rb +++ b/app/models/project_services/custom_issue_tracker_service.rb @@ -3,11 +3,11 @@ class CustomIssueTrackerService < IssueTrackerService validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? - def default_title + def title 'Custom Issue Tracker' end - def default_description + def description s_('IssueTracker|Custom issue tracker') end @@ -17,8 +17,6 @@ class CustomIssueTrackerService < IssueTrackerService def fields [ - { type: 'text', name: 'title', placeholder: title }, - { type: 'text', name: 'description', placeholder: description }, { type: 'text', name: 'project_url', placeholder: 'Project url', required: true }, { type: 'text', name: 'issues_url', placeholder: 'Issue url', required: true }, { type: 'text', name: 'new_issue_url', placeholder: 'New Issue url', required: true } diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb index ec28602b5e6ffaf55ec2ac13af0ecfcec97b70c7..b3f44e040bc11db9061ebc58f903b87fd3b20114 100644 --- a/app/models/project_services/gitlab_issue_tracker_service.rb +++ b/app/models/project_services/gitlab_issue_tracker_service.rb @@ -7,11 +7,11 @@ class GitlabIssueTrackerService < IssueTrackerService default_value_for :default, true - def default_title + def title 'GitLab' end - def default_description + def description s_('IssueTracker|GitLab issue tracker') end diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index f5d6ae10469ded833b1e231d14d10e84ff91f2b2..694374e95488f5ba3f145e20d2909958f333c97f 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -25,28 +25,6 @@ class IssueTrackerService < Service end end - # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 - def title - if title_attribute = read_attribute(:title) - title_attribute - elsif self.properties && self.properties['title'].present? - self.properties['title'] - else - default_title - end - end - - # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 - def description - if description_attribute = read_attribute(:description) - description_attribute - elsif self.properties && self.properties['description'].present? - self.properties['description'] - else - default_description - end - end - def handle_properties # this has been moved from initialize_properties and should be improved # as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 @@ -54,13 +32,6 @@ class IssueTrackerService < Service @legacy_properties_data = properties.dup data_values = properties.slice!('title', 'description') - properties.each do |key, _| - current_value = self.properties.delete(key) - value = attribute_changed?(key) ? attribute_change(key).last : current_value - - write_attribute(key, value) - end - data_values.reject! { |key| data_fields.changed.include?(key) } data_values.slice!(*data_fields.attributes.keys) data_fields.assign_attributes(data_values) if data_values.present? @@ -102,7 +73,6 @@ class IssueTrackerService < Service def fields [ - { type: 'text', name: 'description', placeholder: description }, { type: 'text', name: 'project_url', placeholder: 'Project url', required: true }, { type: 'text', name: 'issues_url', placeholder: 'Issue url', required: true }, { type: 'text', name: 'new_issue_url', placeholder: 'New Issue url', required: true } @@ -117,8 +87,6 @@ class IssueTrackerService < Service def set_default_data return unless issues_tracker.present? - self.title ||= issues_tracker['title'] - # we don't want to override if we have set something return if project_url || issues_url || new_issue_url diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index bb4d35cad226a02652fbded1ee94570fc7830ab2..8c97547f41682db08844420d172b759fb794ac71 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -64,8 +64,6 @@ class JiraService < IssueTrackerService def set_default_data return unless issues_tracker.present? - self.title ||= issues_tracker['title'] - return if url data_fields.url ||= issues_tracker['url'] @@ -103,11 +101,11 @@ class JiraService < IssueTrackerService [Jira service documentation](#{help_page_url('user/project/integrations/jira')})." end - def default_title + def title 'Jira' end - def default_description + def description s_('JiraService|Jira issue tracker') end diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb index a4ca0d20669f89952fa44a7ae01bd4c71a844e2d..df78520d65f70152a5a91d8c226886e810fae26c 100644 --- a/app/models/project_services/redmine_service.rb +++ b/app/models/project_services/redmine_service.rb @@ -3,11 +3,11 @@ class RedmineService < IssueTrackerService validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? - def default_title + def title 'Redmine' end - def default_description + def description s_('IssueTracker|Redmine issue tracker') end diff --git a/app/models/project_services/youtrack_service.rb b/app/models/project_services/youtrack_service.rb index 40203ad692dbcc550ddb1d72f44c36df7a06312c..7fb3bde44a51c3bfe554d065a433d605103c78ba 100644 --- a/app/models/project_services/youtrack_service.rb +++ b/app/models/project_services/youtrack_service.rb @@ -12,11 +12,11 @@ class YoutrackService < IssueTrackerService end end - def default_title + def title 'YouTrack' end - def default_description + def description s_('IssueTracker|YouTrack issue tracker') end @@ -26,7 +26,6 @@ class YoutrackService < IssueTrackerService def fields [ - { type: 'text', name: 'description', placeholder: description }, { type: 'text', name: 'project_url', title: 'Project URL', placeholder: 'Project URL', required: true }, { type: 'text', name: 'issues_url', title: 'Issue URL', placeholder: 'Issue URL', required: true } ] diff --git a/app/models/service.rb b/app/models/service.rb index 04b30930d54e01799c0cc92f7e536ba21d7ad0b7..e310ff9abd2222e6b0557cee91e76a7de4fcf7de 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -7,6 +7,9 @@ class Service < ApplicationRecord include Importable include ProjectServicesLoggable include DataFields + include IgnorableColumns + + ignore_columns %i[title description], remove_with: '13.4', remove_after: '2020-09-22' SERVICE_NAMES = %w[ alerts asana assembla bamboo bugzilla buildkite campfire custom_issue_tracker discord diff --git a/app/services/gpg_keys/destroy_service.rb b/app/services/gpg_keys/destroy_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..cecbfe266112b0f660f4bfdc871ad91bbe1385d6 --- /dev/null +++ b/app/services/gpg_keys/destroy_service.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module GpgKeys + class DestroyService < Keys::BaseService + def execute(key) + key.destroy + end + end +end diff --git a/app/services/jira/requests/base.rb b/app/services/jira/requests/base.rb index 7521c7610cb0d6fda0a1d29875ef6490ecb3d954..0934730d10ca3d590f9bbb47fd4bd465d3819513 100644 --- a/app/services/jira/requests/base.rb +++ b/app/services/jira/requests/base.rb @@ -5,22 +5,16 @@ module Jira class Base include ProjectServicesLoggable - PER_PAGE = 50 + attr_reader :jira_service, :project, :query - attr_reader :jira_service, :project, :limit, :start_at, :query - - def initialize(jira_service, limit: PER_PAGE, start_at: 0, query: nil) + def initialize(jira_service, query: nil) @project = jira_service&.project @jira_service = jira_service - - @limit = limit - @start_at = start_at - @query = query + @query = query end def execute return ServiceResponse.error(message: _('Jira service not configured.')) unless jira_service&.active? - return ServiceResponse.success(payload: empty_payload) if limit.to_i <= 0 request end diff --git a/app/services/jira/requests/projects.rb b/app/services/jira/requests/projects.rb index da46450321150908613abb812ad6cd473c88f345..afb3b45fac1063df9e7cf1a5520cc3360dcac8c2 100644 --- a/app/services/jira/requests/projects.rb +++ b/app/services/jira/requests/projects.rb @@ -9,19 +9,24 @@ module Jira override :url def url - '/rest/api/2/project/search?query=%{query}&maxResults=%{limit}&startAt=%{start_at}' % - { query: CGI.escape(query.to_s), limit: limit.to_i, start_at: start_at.to_i } + '/rest/api/2/project' end override :build_service_response def build_service_response(response) - return ServiceResponse.success(payload: empty_payload) unless response['values'].present? + return ServiceResponse.success(payload: empty_payload) unless response.present? - ServiceResponse.success(payload: { projects: map_projects(response), is_last: response['isLast'] }) + ServiceResponse.success(payload: { projects: map_projects(response), is_last: true }) end def map_projects(response) - response['values'].map { |v| JIRA::Resource::Project.build(client, v) } + response.map { |v| JIRA::Resource::Project.build(client, v) }.select(&method(:match_query?)) + end + + def match_query?(jira_project) + query = self.query.to_s.downcase + + jira_project&.key&.downcase&.include?(query) || jira_project&.name&.downcase&.include?(query) end def empty_payload diff --git a/app/views/admin/appearances/show.html.haml b/app/views/admin/appearances/show.html.haml index ccf6f960cf265c2304db03e709a09f75116c2550..77a08913666742d53fa572bc819c1647bcbb51ae 100644 --- a/app/views/admin/appearances/show.html.haml +++ b/app/views/admin/appearances/show.html.haml @@ -1,4 +1,4 @@ -- page_title "Appearance" +- page_title _("Appearance") - @content_class = "limit-container-width" unless fluid_layout = render 'form' diff --git a/app/views/admin/applications/edit.html.haml b/app/views/admin/applications/edit.html.haml index 13c408914bb116ec0203999c8dc8a5c1a182c0f9..4f737a14e12f2c6fc7b58371272c4f885ed629c1 100644 --- a/app/views/admin/applications/edit.html.haml +++ b/app/views/admin/applications/edit.html.haml @@ -1,6 +1,6 @@ -- add_to_breadcrumbs "Applications", admin_applications_path +- add_to_breadcrumbs _("Applications"), admin_applications_path - breadcrumb_title @application.name -- page_title "Edit", @application.name, "Applications" +- page_title _("Edit"), @application.name, _("Applications") %h3.page-title Edit application - @url = admin_application_path(@application) diff --git a/app/views/admin/applications/index.html.haml b/app/views/admin/applications/index.html.haml index c3861f335b8d2742d7e47145367176c1c1e5e021..0119cabf1ad5987b82475c47d770e488fba25969 100644 --- a/app/views/admin/applications/index.html.haml +++ b/app/views/admin/applications/index.html.haml @@ -1,4 +1,4 @@ -- page_title "Applications" +- page_title _("Applications") %h3.page-title System OAuth applications %p.light diff --git a/app/views/admin/applications/new.html.haml b/app/views/admin/applications/new.html.haml index 346c58877d94d3ddf495ca9b67782eb884432a11..4d4b6b0c994033c987cfb3a47ee54442f93ebe2b 100644 --- a/app/views/admin/applications/new.html.haml +++ b/app/views/admin/applications/new.html.haml @@ -1,5 +1,5 @@ -- breadcrumb_title "Applications" -- page_title "New Application" +- breadcrumb_title _("Applications") +- page_title _("New Application") %h3.page-title New application - @url = admin_applications_path diff --git a/app/views/admin/applications/show.html.haml b/app/views/admin/applications/show.html.haml index 146674a2fac89c3f785029a76c1bc4f7caeaea42..b39a753d010415f1bde71ac0e59681f0dd7c4682 100644 --- a/app/views/admin/applications/show.html.haml +++ b/app/views/admin/applications/show.html.haml @@ -1,4 +1,4 @@ -- page_title @application.name, "Applications" +- page_title @application.name, _("Applications") %h3.page-title Application: #{@application.name} diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml index 1001a69b787f91f07281e95f57c5a892a8dd23e0..bbb47e29bb960fd27904baeeaa1db2a0e199d135 100644 --- a/app/views/admin/background_jobs/show.html.haml +++ b/app/views/admin/background_jobs/show.html.haml @@ -1,4 +1,4 @@ -- page_title "Background Jobs" +- page_title _("Background Jobs") %h3.page-title Background Jobs %p.light GitLab uses #{link_to "sidekiq", "http://sidekiq.org/"} library for async job processing diff --git a/app/views/admin/broadcast_messages/edit.html.haml b/app/views/admin/broadcast_messages/edit.html.haml index 8cbc4597e32942d6757fd8374e85996dcac6c0f7..569aaa29cc45464fe03f92f916e97daa7f1b793f 100644 --- a/app/views/admin/broadcast_messages/edit.html.haml +++ b/app/views/admin/broadcast_messages/edit.html.haml @@ -1,4 +1,4 @@ -- breadcrumb_title "Messages" -- page_title "Broadcast Messages" +- breadcrumb_title _("Messages") +- page_title _("Broadcast Messages") = render 'form' diff --git a/app/views/admin/broadcast_messages/index.html.haml b/app/views/admin/broadcast_messages/index.html.haml index e7a7ee965080ab37b22f4a33adfdd4178c16213a..bca74f71c5c9896a288b243f569ecea693325c60 100644 --- a/app/views/admin/broadcast_messages/index.html.haml +++ b/app/views/admin/broadcast_messages/index.html.haml @@ -1,5 +1,5 @@ -- breadcrumb_title "Messages" -- page_title "Broadcast Messages" +- breadcrumb_title _("Messages") +- page_title _("Broadcast Messages") %h3.page-title Broadcast Messages diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 951e5364ad8bf9520cb242d1d26a5b2146a30868..3afed99334b80875f15afea577facbdf8f7e9c4f 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -1,4 +1,5 @@ -- breadcrumb_title "Dashboard" +- breadcrumb_title _("Dashboard") +- page_title _("Dashboard") - if show_license_breakdown? = render_if_exists 'admin/licenses/breakdown', license: @license diff --git a/app/views/admin/deploy_keys/new.html.haml b/app/views/admin/deploy_keys/new.html.haml index 9a563a5bc78563050880167c2f6ac4cdb32024d5..f43c1447f094f920ccc9cea778d6aae4eff87f81 100644 --- a/app/views/admin/deploy_keys/new.html.haml +++ b/app/views/admin/deploy_keys/new.html.haml @@ -1,4 +1,4 @@ -- page_title 'New Deploy Key' +- page_title _('New Deploy Key') %h3.page-title New public deploy key %hr diff --git a/app/views/admin/gitaly_servers/index.html.haml b/app/views/admin/gitaly_servers/index.html.haml index 9b24f411a75d5d44c5ea216db1b5212f7cde2e0c..0b06f145687250420a6e83e9020db9c5f691989b 100644 --- a/app/views/admin/gitaly_servers/index.html.haml +++ b/app/views/admin/gitaly_servers/index.html.haml @@ -1,4 +1,5 @@ - breadcrumb_title _("Gitaly Servers") +- page_title _("Gitaly Servers") %h3.page-title= _("Gitaly Servers") %hr diff --git a/app/views/admin/hook_logs/show.html.haml b/app/views/admin/hook_logs/show.html.haml index 86729dbe7bce2c25ff42e5e6548f089996532e78..e0256e66376ce5efe1f955ba3f2fb1f1b650984e 100644 --- a/app/views/admin/hook_logs/show.html.haml +++ b/app/views/admin/hook_logs/show.html.haml @@ -1,4 +1,4 @@ -- page_title 'Request details' +- page_title _('Request details') %h3.page-title Request details diff --git a/app/views/admin/jobs/index.html.haml b/app/views/admin/jobs/index.html.haml index f1bdd52b3996e3e4c07cd120ee36425ad3f2f258..32c0a801a1ddc1e619cde8163884f42c7aa9a730 100644 --- a/app/views/admin/jobs/index.html.haml +++ b/app/views/admin/jobs/index.html.haml @@ -1,4 +1,5 @@ -- breadcrumb_title "Jobs" +- breadcrumb_title _("Jobs") +- page_title _("Jobs") .top-area.scrolling-tabs-container.inner-page-scroll-tabs - build_path_proc = ->(scope) { admin_jobs_path(scope: scope) } diff --git a/app/views/admin/keys/show.html.haml b/app/views/admin/keys/show.html.haml index 9ee77c77398bb0d59a79514e04a76efd10c23958..03cc0ae15be03da1b70f260b5c80716d14a6b4a4 100644 --- a/app/views/admin/keys/show.html.haml +++ b/app/views/admin/keys/show.html.haml @@ -1,2 +1,2 @@ -- page_title @key.title, "Keys" +- page_title @key.title, _("Keys") = render "profiles/keys/key_details", admin: true diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index f9d42d3f53b913f5bae563f0df99bc1b5ae04334..1edfedb00f83ef3ceb5700597caac313896c1252 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -1,6 +1,6 @@ -- add_to_breadcrumbs "Projects", admin_projects_path +- add_to_breadcrumbs _("Projects"), admin_projects_path - breadcrumb_title @project.full_name -- page_title @project.full_name, "Projects" +- page_title @project.full_name, _("Projects") - @content_class = "admin-projects" %h3.page-title diff --git a/app/views/admin/requests_profiles/index.html.haml b/app/views/admin/requests_profiles/index.html.haml index efc16bb4d3b7706d4ad31fc9c90607b0c0496b52..b7a4401d90ed6f39d6e7663e3189249af5106f41 100644 --- a/app/views/admin/requests_profiles/index.html.haml +++ b/app/views/admin/requests_profiles/index.html.haml @@ -1,4 +1,4 @@ -- page_title 'Requests Profiles' +- page_title _('Requests Profiles') %h3.page-title = page_title diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml index 59e28a3b2447dbb0578cb83f765881e24b9e1496..08d658194768f3a57e579c8103156811041e9bc2 100644 --- a/app/views/admin/runners/index.html.haml +++ b/app/views/admin/runners/index.html.haml @@ -1,4 +1,5 @@ - breadcrumb_title _('Runners') +- page_title _('Runners') .row .col-sm-6 diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml index 0120d4038b94f3d7b0ebd3ff48b8673f95bcc910..0c2b9bab357683979207e5568bccc24e640a19a1 100644 --- a/app/views/admin/runners/show.html.haml +++ b/app/views/admin/runners/show.html.haml @@ -9,6 +9,7 @@ %span.runner-state.runner-state-specific Specific +- page_title _("Runners") - add_to_breadcrumbs _("Runners"), admin_runners_path - breadcrumb_title "##{@runner.id}" diff --git a/app/views/admin/services/edit.html.haml b/app/views/admin/services/edit.html.haml index 558fe3ab15d1b3b915d9216906209a262e79ef72..d13b5a34dac9678a26e00c079b1e2f9fa19e4fd9 100644 --- a/app/views/admin/services/edit.html.haml +++ b/app/views/admin/services/edit.html.haml @@ -1,6 +1,6 @@ -- add_to_breadcrumbs "Service Templates", admin_application_settings_services_path +- add_to_breadcrumbs _("Service Templates"), admin_application_settings_services_path +- page_title @service.title, _("Service Templates") - breadcrumb_title @service.title -- page_title @service.title, "Service Templates" - @content_class = 'limit-container-width' unless fluid_layout = render 'form' diff --git a/app/views/admin/services/index.html.haml b/app/views/admin/services/index.html.haml index b476c9904626d896d2eba4afe2097521ac1f174e..ec343c384703d27f2f67987f37150f7e476ef28d 100644 --- a/app/views/admin/services/index.html.haml +++ b/app/views/admin/services/index.html.haml @@ -1,4 +1,4 @@ -- page_title "Service Templates" +- page_title _("Service Templates") %h3.page-title Service templates %p.light= s_('AdminSettings|Service template allows you to set default values for integrations') diff --git a/app/views/admin/spam_logs/index.html.haml b/app/views/admin/spam_logs/index.html.haml index b45d3e4823b1a8e86ba9d134915b4a21cd1eea15..40fbc559d72484086b74688d08665f820d8ee0e8 100644 --- a/app/views/admin/spam_logs/index.html.haml +++ b/app/views/admin/spam_logs/index.html.haml @@ -1,4 +1,4 @@ -- page_title "Spam Logs" +- page_title _("Spam Logs") %h3.page-title Spam Logs %hr - if @spam_logs.present? diff --git a/app/views/admin/users/edit.html.haml b/app/views/admin/users/edit.html.haml index 3b6fd71500d7145660c8bffa866bab18a9821521..7d10e839cd69eeeb5714783edf4952b7e44a058e 100644 --- a/app/views/admin/users/edit.html.haml +++ b/app/views/admin/users/edit.html.haml @@ -1,4 +1,4 @@ -- page_title "Edit", @user.name, "Users" +- page_title _("Edit"), @user.name, _("Users") %h3.page-title Edit user: #{@user.name} %hr diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index ecbabab3e7f41eb7a18f85b6fe81a0f5385a6ded..69df8fa2198a20e9ac0bbfed9472354d5c927878 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,4 +1,4 @@ -- page_title "Users" +- page_title _("Users") .top-area.scrolling-tabs-container.inner-page-scroll-tabs .fade-left diff --git a/app/views/admin/users/keys.html.haml b/app/views/admin/users/keys.html.haml index 103bbb3b06328fb64f11a798ab984c0f4e31ac93..5f9d11af7c104c65cdbc5fda981353640ffe4c88 100644 --- a/app/views/admin/users/keys.html.haml +++ b/app/views/admin/users/keys.html.haml @@ -1,5 +1,5 @@ -- add_to_breadcrumbs "Users", admin_users_path +- add_to_breadcrumbs _("Users"), admin_users_path - breadcrumb_title @user.name -- page_title "SSH Keys", @user.name, "Users" +- page_title _("SSH Keys"), @user.name, _("Users") = render 'admin/users/head' = render 'profiles/keys/key_table', admin: true diff --git a/app/views/admin/users/new.html.haml b/app/views/admin/users/new.html.haml index bfc36ed7373dd998f8990fdd37de4ec585b2c4ac..e5e6790b789611f5fb2c36b9978774f5fcf260c7 100644 --- a/app/views/admin/users/new.html.haml +++ b/app/views/admin/users/new.html.haml @@ -1,4 +1,4 @@ -- page_title "New User" +- page_title _("New User") %h3.page-title New user %hr diff --git a/app/views/admin/users/projects.html.haml b/app/views/admin/users/projects.html.haml index e6da81831ab38b76032a273bab9bd68b2f7e0fb2..5a11ee7e8363ebf03e2dba70af2b7df022548341 100644 --- a/app/views/admin/users/projects.html.haml +++ b/app/views/admin/users/projects.html.haml @@ -1,6 +1,6 @@ -- add_to_breadcrumbs "Users", admin_users_path +- add_to_breadcrumbs _("Users"), admin_users_path - breadcrumb_title @user.name -- page_title "Groups and projects", @user.name, "Users" +- page_title _("Groups and projects"), @user.name, _("Users") = render 'admin/users/head' - if @user.groups.any? diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index c2ceb7e7cbb7bddb677bcf84bf4ef6a287077c66..2bc39a23b2d636b0f1f83a1c06fe991728d86a41 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -1,6 +1,6 @@ -- add_to_breadcrumbs "Users", admin_users_path +- add_to_breadcrumbs _("Users"), admin_users_path - breadcrumb_title @user.name -- page_title @user.name, "Users" +- page_title @user.name, _("Users") = render 'admin/users/head' .row diff --git a/app/views/dashboard/activity.html.haml b/app/views/dashboard/activity.html.haml index d7306f5932d47c340b390c52ceb52541215a1e9e..1e93613e97852641f6beaa35bea7cfa80b4fb8a5 100644 --- a/app/views/dashboard/activity.html.haml +++ b/app/views/dashboard/activity.html.haml @@ -5,8 +5,8 @@ = render_dashboard_gold_trial(current_user) -- page_title "Activity" -- header_title "Activity", activity_dashboard_path +- page_title _("Activity") +- header_title _("Activity"), activity_dashboard_path = render "projects/last_push" = render 'dashboard/activity_head' diff --git a/app/views/dashboard/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml index d1d8d970b593b9d74c3af78f6979188ba50bf4ae..9536ff940f550ba1c514e7251b2054350dede009 100644 --- a/app/views/dashboard/groups/index.html.haml +++ b/app/views/dashboard/groups/index.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true -- page_title "Groups" -- header_title "Groups", dashboard_groups_path +- page_title _("Groups") +- header_title _("Groups"), dashboard_groups_path = render_dashboard_gold_trial(current_user) = render 'dashboard/groups_head' diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml index b9be6028b72b04189371a853aaed8ded19aa2469..a0c1c314a851e90d52a050a1219a104d54aef5b4 100644 --- a/app/views/dashboard/milestones/index.html.haml +++ b/app/views/dashboard/milestones/index.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true -- page_title 'Milestones' -- header_title 'Milestones', dashboard_milestones_path +- page_title _('Milestones') +- header_title _('Milestones'), dashboard_milestones_path .page-title-holder.d-flex.align-items-center %h1.page-title= _('Milestones') diff --git a/app/views/dashboard/projects/index.html.haml b/app/views/dashboard/projects/index.html.haml index d2aa07bab22a28802aab4090c44b6c18e6134da4..2e7eab87af30c5ce44085081dc4975d964b9a99e 100644 --- a/app/views/dashboard/projects/index.html.haml +++ b/app/views/dashboard/projects/index.html.haml @@ -5,8 +5,8 @@ = render_dashboard_gold_trial(current_user) -- page_title "Projects" -- header_title "Projects", dashboard_projects_path +- page_title _("Projects") +- header_title _("Projects"), dashboard_projects_path = render "projects/last_push" - if show_projects?(@projects, params) diff --git a/app/views/dashboard/snippets/index.html.haml b/app/views/dashboard/snippets/index.html.haml index 2f0cc76f2e0c6c6bc3e1cd8f5f748c315e82e8a2..68457ab33f73be93bdb9d677312a0b1f9f728eec 100644 --- a/app/views/dashboard/snippets/index.html.haml +++ b/app/views/dashboard/snippets/index.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true -- page_title "Snippets" -- header_title "Snippets", dashboard_snippets_path +- page_title _("Snippets") +- header_title _("Snippets"), dashboard_snippets_path - button_path = new_snippet_path if can?(current_user, :create_snippet) = render 'dashboard/snippets_head' diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml index cfc637592d35d2cc2d3968e293cd72a4e03764ad..9fca580a870a75b226229c42f95257772b023202 100644 --- a/app/views/dashboard/todos/index.html.haml +++ b/app/views/dashboard/todos/index.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true -- page_title "To-Do List" -- header_title "To-Do List", dashboard_todos_path +- page_title _("To-Do List") +- header_title _("To-Do List"), dashboard_todos_path = render_dashboard_gold_trial(current_user) diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index 9fb5e27b6928b4b1c7688d5758f3320bdef2499f..fb00e1b43845e052ee7d6157e11c30587496ecb8 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -1,4 +1,4 @@ -- page_title "Sign up" +- page_title _("Sign up") - if experiment_enabled?(:signup_flow) .row .col-lg-7 diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index fd6d8f3f76981a66df8988043f185a2cc52fc028..c466d2ce93655ac3d3a097f1aa5a3c36e3dc4c3d 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -1,4 +1,4 @@ -- page_title "Sign in" +- page_title _("Sign in") #signin-container - if any_form_based_providers_enabled? diff --git a/app/views/explore/snippets/index.html.haml b/app/views/explore/snippets/index.html.haml index d23c8301b10a434a8a5054aae7905e478a23fd8c..bf861e30b3a1b079fc3ac562ea0b6bfd697734a8 100644 --- a/app/views/explore/snippets/index.html.haml +++ b/app/views/explore/snippets/index.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true -- page_title "Snippets" -- header_title "Snippets", snippets_path +- page_title _("Snippets") +- header_title _("Snippets"), snippets_path - if current_user = render 'dashboard/snippets_head' diff --git a/app/views/groups/activity.html.haml b/app/views/groups/activity.html.haml index cb7dab2633237bf6f428194218f4b30e8a923f26..bc75fada93724f4cab9a800a8bdbddfa08f54d05 100644 --- a/app/views/groups/activity.html.haml +++ b/app/views/groups/activity.html.haml @@ -1,7 +1,7 @@ = content_for :meta_tags do = auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity") -- page_title "Activity" +- page_title _("Activity") %section.activities = render 'activities' diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 2e58517fdc77aa2aa644b9f66c4f1390d1d39168..1e04b2761f61b11d40f6eb6f5dd35142d6abbdf3 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -1,4 +1,5 @@ - breadcrumb_title _("General Settings") +- page_title _("General Settings") - @content_class = "limit-container-width" unless fluid_layout - expanded = expanded_by_default? diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index 1cb1cc45bdb68ea4466878bef55c39fc1e6acf25..59432e5f01554230b4e220062896dd8a0ddc0b9b 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -1,6 +1,6 @@ - @can_bulk_update = can?(current_user, :admin_issue, @group) && @group.feature_available?(:group_bulk_edit) -- page_title "Issues" +- page_title _("Issues") = content_for :meta_tags do = auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{@group.name} issues") diff --git a/app/views/groups/labels/edit.html.haml b/app/views/groups/labels/edit.html.haml index 586b0f6ebfa3aa8faddb81c97a35373b5e2343fe..fbab4f8a250252b3031ea16be5ac84f500e8fd71 100644 --- a/app/views/groups/labels/edit.html.haml +++ b/app/views/groups/labels/edit.html.haml @@ -1,6 +1,6 @@ - add_to_breadcrumbs _("Labels"), group_labels_path(@group) - breadcrumb_title _("Edit") -- page_title "Edit", @label.name, _("Labels") +- page_title _("Edit"), @label.name, _("Labels") %h3.page-title Edit Label diff --git a/app/views/groups/labels/index.html.haml b/app/views/groups/labels/index.html.haml index 41c1d3e84b7b8eb07bab4d6524f589fb751e0237..ec6694672ae8547961933cb139df442abb6e4eec 100644 --- a/app/views/groups/labels/index.html.haml +++ b/app/views/groups/labels/index.html.haml @@ -1,4 +1,4 @@ -- page_title 'Labels' +- page_title _('Labels') - can_admin_label = can?(current_user, :admin_label, @group) - search = params[:search] - subscribed = params[:subscribed] diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml index 0780fab513b13df1ac1f7f6569ca50414bf06859..1828f850d35ff296924b2356e00effa8bc0d333c 100644 --- a/app/views/groups/merge_requests.html.haml +++ b/app/views/groups/merge_requests.html.haml @@ -1,6 +1,6 @@ - @can_bulk_update = can?(current_user, :admin_merge_request, @group) && @group.feature_available?(:group_bulk_edit) -- page_title "Merge Requests" +- page_title _("Merge Requests") - if group_merge_requests_count(state: 'all').zero? = render 'shared/empty_states/merge_requests', project_select_button: true diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index 03407adb57d58d74ebef39ab9535268c208d03a0..89ea0c6c7d9918e326542989db860bc32c42f121 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -1,4 +1,4 @@ -- page_title "Milestones" +- page_title _("Milestones") .top-area = render 'shared/milestones_filter', counts: @milestone_states diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml index 8b01e54474aec388fd08bbe3a5bd27a8a60b600c..c9cf8c5a76c5b03b618329e2b849256be5bb1f78 100644 --- a/app/views/groups/projects.html.haml +++ b/app/views/groups/projects.html.haml @@ -1,4 +1,5 @@ -- breadcrumb_title "Projects" +- breadcrumb_title _("Projects") +- page_title _("Projects") .card.prepend-top-default .card-header diff --git a/app/views/groups/settings/ci_cd/show.html.haml b/app/views/groups/settings/ci_cd/show.html.haml index 8c9b859e127ab08bc32865f3411c93ad1c5f517d..366d7dd5afe8f08e4c7c7359c41c2112bf381022 100644 --- a/app/views/groups/settings/ci_cd/show.html.haml +++ b/app/views/groups/settings/ci_cd/show.html.haml @@ -1,5 +1,5 @@ -- breadcrumb_title "CI / CD Settings" -- page_title "CI / CD" +- breadcrumb_title _("CI / CD Settings") +- page_title _("CI / CD") - expanded = expanded_by_default? - general_expanded = @group.errors.empty? ? expanded : true diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 7e5bf6ddde17a4fb3c20e07c09dcaa684257b060..d896b28944e23d6efa9c6e9f6b8be6db1a8d8553 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -1,4 +1,5 @@ - breadcrumb_title _("Details") +- page_title _("Groups") - @content_class = "limit-container-width" unless fluid_layout = content_for :meta_tags do diff --git a/app/views/help/instance_configuration.html.haml b/app/views/help/instance_configuration.html.haml index 99576d45f76247518d4fab739e5ec98f076a7093..260566b1441b52240eeadaec2f67fc01ac1e22f6 100644 --- a/app/views/help/instance_configuration.html.haml +++ b/app/views/help/instance_configuration.html.haml @@ -1,4 +1,4 @@ -- page_title 'Instance Configuration' +- page_title _('Instance Configuration') .documentation.md %h1 Instance Configuration diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index d71650ae50c33406bcd35e04917223ed34d23882..5c216ee1ec073a4ab32d4734760a15759b862887 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -1,4 +1,4 @@ -- page_title "UI Development Kit", "Help" +- page_title _("UI Development Kit"), _("Help") - lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum nisi sapien, non consequat lectus aliquam ultrices. Suspendisse sodales est euismod nunc condimentum, a consectetur diam ornare." - link_classes = "flex-grow-1 mx-1 " diff --git a/app/views/ide/_show.html.haml b/app/views/ide/_show.html.haml index b871f0363f3afa2ad38475c65da385aea7760157..d0384fd50bc29753f2511985789b15866f1ff73f 100644 --- a/app/views/ide/_show.html.haml +++ b/app/views/ide/_show.html.haml @@ -1,5 +1,5 @@ - @body_class = 'ide-layout' -- page_title 'IDE' +- page_title _('IDE') - content_for :page_specific_javascripts do = stylesheet_link_tag 'page_bundles/ide' diff --git a/app/views/import/bitbucket_server/new.html.haml b/app/views/import/bitbucket_server/new.html.haml index 2eac8d0c5a1aaccaec3e8a2a0687bc1f26687ca1..18ccad9ca308e973c8aa0abe8114931f77b39ae2 100644 --- a/app/views/import/bitbucket_server/new.html.haml +++ b/app/views/import/bitbucket_server/new.html.haml @@ -1,7 +1,7 @@ - title = _('Bitbucket Server Import') - page_title title - breadcrumb_title title -- header_title "Projects", root_path +- header_title _("Projects"), root_path %h3.page-title = icon 'bitbucket-square', text: _('Import repositories from Bitbucket Server') diff --git a/app/views/import/bitbucket_server/status.html.haml b/app/views/import/bitbucket_server/status.html.haml index 7523b8f7b1caf378bfe05d736fefd356f7345f48..c4b30a8c17eddb8ec1dbc95a38bf2f8622f1baa0 100644 --- a/app/views/import/bitbucket_server/status.html.haml +++ b/app/views/import/bitbucket_server/status.html.haml @@ -1,5 +1,5 @@ -- page_title 'Bitbucket Server import' -- header_title 'Projects', root_path +- page_title _('Bitbucket Server import') +- header_title _('Projects'), root_path %h3.page-title %i.fa.fa-bitbucket-square diff --git a/app/views/import/manifest/new.html.haml b/app/views/import/manifest/new.html.haml index df00c4d2179d99c6dab7f9cce8d647256d871fb9..852f269f2ed78146b25e7cc0e8d7f8980f96ff0b 100644 --- a/app/views/import/manifest/new.html.haml +++ b/app/views/import/manifest/new.html.haml @@ -1,5 +1,5 @@ -- page_title "Manifest file import" -- header_title "Projects", root_path +- page_title _("Manifest file import") +- header_title _("Projects"), root_path %h3.page-title = _('Manifest file import') diff --git a/app/views/import/manifest/status.html.haml b/app/views/import/manifest/status.html.haml index 3d4abc32b8897521d759ca325f9029b36075bada..e85162ad1b42fa286142fd00e9953014cd201280 100644 --- a/app/views/import/manifest/status.html.haml +++ b/app/views/import/manifest/status.html.haml @@ -1,5 +1,5 @@ -- page_title "Manifest import" -- header_title "Projects", root_path +- page_title _("Manifest import") +- header_title _("Projects"), root_path - provider = 'manifest' %h3.page-title diff --git a/app/views/instance_statistics/cohorts/index.html.haml b/app/views/instance_statistics/cohorts/index.html.haml index 5333f8b7a1f5a579ad8678c9a37213e5b59bb86e..771e988e256bdcc59019d5da09254e8241bce402 100644 --- a/app/views/instance_statistics/cohorts/index.html.haml +++ b/app/views/instance_statistics/cohorts/index.html.haml @@ -1,4 +1,5 @@ - breadcrumb_title _("Cohorts") +- page_title _("Cohorts") - if @cohorts = render 'cohorts_table' diff --git a/app/views/layouts/header/_new_dropdown.haml b/app/views/layouts/header/_new_dropdown.haml index 3cbfb24a86816af1ac1fefbb113e2c8ca299b680..4bfac76ec5b1be13737ec737907590b97e02185a 100644 --- a/app/views/layouts/header/_new_dropdown.haml +++ b/app/views/layouts/header/_new_dropdown.haml @@ -15,6 +15,7 @@ %li= link_to _('New project'), new_project_path(namespace_id: @group.id) - if create_group_subgroup %li= link_to _('New subgroup'), new_group_path(parent_id: @group.id) + = render_if_exists 'layouts/header/create_epic_new_dropdown_item' %li.divider %li.dropdown-bold-header GitLab diff --git a/app/views/layouts/snippets.html.haml b/app/views/layouts/snippets.html.haml index cde2b467392c6913927aba83c28f71955b3829c6..6cc53ba3342a7e7ed507a5416998fde8187fe3c0 100644 --- a/app/views/layouts/snippets.html.haml +++ b/app/views/layouts/snippets.html.haml @@ -1,3 +1,4 @@ +- page_title _("Snippets") - header_title _("Snippets"), snippets_path - snippets_upload_path = snippets_upload_path(@snippet, current_user) diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 78fdcdef3c46169780a8b2508d7e103652e96916..f5ea805cf85469e329983ee9786b977bc3a2ba31 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -1,4 +1,5 @@ - breadcrumb_title s_("Profiles|Edit Profile") +- page_title s_("Profiles|Edit Profile") - @content_class = "limit-container-width" unless fluid_layout - gravatar_link = link_to Gitlab.config.gravatar.host, 'https://' + Gitlab.config.gravatar.host diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml index 7abac2d14e488e8a2b3be60ee0c434004b05b70d..ff56cb537201f91450598cfbbcd5dd7fd7ff67d1 100644 --- a/app/views/projects/artifacts/browse.html.haml +++ b/app/views/projects/artifacts/browse.html.haml @@ -1,5 +1,5 @@ - breadcrumb_title _('Artifacts') -- page_title @path.presence, 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs' +- page_title @path.presence, _('Artifacts'), "#{@build.name} (##{@build.id})", _('Jobs') = render "projects/jobs/header" diff --git a/app/views/projects/artifacts/file.html.haml b/app/views/projects/artifacts/file.html.haml index 808b4acc8f3a79d1af6d12c2168658d337288cd8..1ad70506be4790642704ea6f3c198f7107344d8b 100644 --- a/app/views/projects/artifacts/file.html.haml +++ b/app/views/projects/artifacts/file.html.haml @@ -1,4 +1,4 @@ -- page_title @path, 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs' +- page_title @path, _('Artifacts'), "#{@build.name} (##{@build.id})", _('Jobs') = render "projects/jobs/header" diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml index 0591c3180ea9500f349ea969d5a787d41ad16dc9..a2d6b2e18a91e33d1a87715dcbef2336a8414d23 100644 --- a/app/views/projects/blame/show.html.haml +++ b/app/views/projects/blame/show.html.haml @@ -1,4 +1,4 @@ -- page_title "Blame", @blob.path, @ref +- page_title _("Blame"), @blob.path, @ref - link_icon = icon("link") #blob-content-holder.tree-holder diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml index 3d84adbc49a213a46308297111cc8022fe4130cd..1319c58eb38bbef1bdbdf30c27f2d153fe4dfc32 100644 --- a/app/views/projects/blob/edit.html.haml +++ b/app/views/projects/blob/edit.html.haml @@ -1,5 +1,5 @@ -- breadcrumb_title "Repository" -- page_title "Edit", @blob.path, @ref +- breadcrumb_title _("Repository") +- page_title _("Edit"), @blob.path, @ref - unless Feature.enabled?(:monaco_blobs) - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml index f9abcffeeb42c5f7bbcaf9c0d7644b7be16f6e60..2420c4a4bd533201c1b7f4f95ffe5916120757c4 100644 --- a/app/views/projects/blob/new.html.haml +++ b/app/views/projects/blob/new.html.haml @@ -1,5 +1,5 @@ -- breadcrumb_title "Repository" -- page_title "New File", @path.presence, @ref +- breadcrumb_title _("Repository") +- page_title _("New File"), @path.presence, @ref - unless Feature.enabled?(:monaco_blobs) - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') diff --git a/app/views/projects/branches/new.html.haml b/app/views/projects/branches/new.html.haml index af8887b0c397b01825642a2446e955891ce86aaf..97e46aaa710cedfc3aa437f26f5192e8501963cd 100644 --- a/app/views/projects/branches/new.html.haml +++ b/app/views/projects/branches/new.html.haml @@ -1,4 +1,4 @@ -- page_title "New Branch" +- page_title _("New Branch") - default_ref = params[:ref] || @project.default_branch - if @error diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml index 02f2b104ce3b8e72a2b663e0d0e8deecb1e8985b..93ee1bed8091e9bc0f7b1630c4150ded306a5579 100644 --- a/app/views/projects/compare/index.html.haml +++ b/app/views/projects/compare/index.html.haml @@ -1,5 +1,5 @@ -- breadcrumb_title "Compare Revisions" -- page_title "Compare" +- breadcrumb_title _("Compare Revisions") +- page_title _("Compare") %h3.page-title = _("Compare Git revisions") diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml index b6c30c680e40093263837f3eae1c96a91e46cdad..090fc602ebb5b1361f65b7bf70db3fdae08153d5 100644 --- a/app/views/projects/cycle_analytics/show.html.haml +++ b/app/views/projects/cycle_analytics/show.html.haml @@ -1,4 +1,4 @@ -- page_title "Value Stream Analytics" +- page_title _("Value Stream Analytics") #cycle-analytics{ "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } } - if @cycle_analytics_no_data diff --git a/app/views/projects/deploy_keys/edit.html.haml b/app/views/projects/deploy_keys/edit.html.haml index 0ce93eef36953b5ce26a4c6d4edb3b9492e0de70..7fa7036245ced0bdd1481c1e5bf9913ae8586e00 100644 --- a/app/views/projects/deploy_keys/edit.html.haml +++ b/app/views/projects/deploy_keys/edit.html.haml @@ -1,4 +1,4 @@ -- page_title 'Edit Deploy Key' +- page_title _('Edit Deploy Key') %h3.page-title= _('Edit Deploy Key') %hr diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index 6b1455acd08f9c36e69a54eaeadb5e27b6b97cfd..68c2af336b3e9fc13c79cee21145e828f2a4d3d5 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -1,5 +1,6 @@ - @content_class = "limit-container-width" unless fluid_layout - breadcrumb_title _("Details") +- page_title _("Details") = render partial: 'flash_messages', locals: { project: @project } diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml index 971107675abafb7ea7cecafe4903f30b0da42e30..3b0555908f6c35485998cf1ea9c6fc98801b44a0 100644 --- a/app/views/projects/find_file/show.html.haml +++ b/app/views/projects/find_file/show.html.haml @@ -1,4 +1,4 @@ -- page_title "Find File", @ref +- page_title _("Find File"), @ref .file-finder-holder.tree-holder.clearfix.js-file-finder{ 'data-file-find-url': "#{escape_javascript(project_files_path(@project, @ref, format: :json))}", 'data-find-tree-url': escape_javascript(project_tree_path(@project, @ref)), 'data-blob-url-template': escape_javascript(project_blob_path(@project, @id || @commit.id)) } .nav-block diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml index bd0ab2c19f25bf01eee8f7dadb2f2bd27f4222b0..58981ca155608f60a5b100d3b3a1406366e46c1b 100644 --- a/app/views/projects/imports/new.html.haml +++ b/app/views/projects/imports/new.html.haml @@ -1,4 +1,4 @@ -- page_title "Import repository" +- page_title _("Import repository") %h3.page-title Import repository diff --git a/app/views/projects/issues/edit.html.haml b/app/views/projects/issues/edit.html.haml index 1b7d878c38c0db14eb88a6146d7f048798a3d426..353ff9c1cc2033f0c5b4161bad0354cfd8edbad7 100644 --- a/app/views/projects/issues/edit.html.haml +++ b/app/views/projects/issues/edit.html.haml @@ -1,4 +1,4 @@ -- page_title "Edit", "#{@issue.title} (#{@issue.to_reference})", "Issues" +- page_title _("Edit"), "#{@issue.title} (#{@issue.to_reference})", _("Issues") %h3.page-title Edit Issue ##{@issue.iid} diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml index 826a62e39d32d2b3796be210210376bb40d8ccb2..cfc423da57aadaa8f09034747a043daccb32d797 100644 --- a/app/views/projects/issues/index.html.haml +++ b/app/views/projects/issues/index.html.haml @@ -1,6 +1,6 @@ - @can_bulk_update = can?(current_user, :admin_issue, @project) -- page_title "Issues" +- page_title _("Issues") - new_issue_email = @project.new_issuable_address(current_user, 'issue') = content_for :meta_tags do diff --git a/app/views/projects/jobs/index.html.haml b/app/views/projects/jobs/index.html.haml index 5acb2af08e42f3a34fa7038b4b477eafce4b183d..4f537ee8014d509a8bc281923d6f3ccce3a257e0 100644 --- a/app/views/projects/jobs/index.html.haml +++ b/app/views/projects/jobs/index.html.haml @@ -1,4 +1,4 @@ -- page_title "Jobs" +- page_title _("Jobs") .top-area - build_path_proc = ->(scope) { project_jobs_path(@project, scope: scope) } diff --git a/app/views/projects/jobs/terminal.html.haml b/app/views/projects/jobs/terminal.html.haml index 5439a4b5d5c02762a8b7d3d6508bacb1a2980bdc..01f40543926047a7aa92c5dea9eaedbdcdf86e6b 100644 --- a/app/views/projects/jobs/terminal.html.haml +++ b/app/views/projects/jobs/terminal.html.haml @@ -1,7 +1,7 @@ -- add_to_breadcrumbs 'Jobs', project_jobs_path(@project) +- add_to_breadcrumbs _('Jobs'), project_jobs_path(@project) - add_to_breadcrumbs "##{@build.id}", project_job_path(@project, @build) -- breadcrumb_title 'Terminal' -- page_title 'Terminal', "#{@build.name} (##{@build.id})", 'Jobs' +- breadcrumb_title _('Terminal') +- page_title _('Terminal'), "#{@build.name} (##{@build.id})", _('Jobs') - content_for :page_specific_javascripts do = stylesheet_link_tag "xterm.css" diff --git a/app/views/projects/labels/edit.html.haml b/app/views/projects/labels/edit.html.haml index b7996f0dad1adca88d41c39360294496ca47d4a6..343900359b4a03d3f7c3ea1b68920846d624c18c 100644 --- a/app/views/projects/labels/edit.html.haml +++ b/app/views/projects/labels/edit.html.haml @@ -1,6 +1,6 @@ -- add_to_breadcrumbs "Labels", project_labels_path(@project) -- breadcrumb_title "Edit" -- page_title "Edit", @label.name, "Labels" +- add_to_breadcrumbs _("Labels"), project_labels_path(@project) +- breadcrumb_title _("Edit") +- page_title _("Edit"), @label.name, _("Labels") %h3.page-title Edit Label diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index 760d81136c69c1ada4c08b9e632282d648db76dd..93ece26357e6142e3b9467720f9b4dd4611d3ba8 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -1,4 +1,4 @@ -- page_title "Labels" +- page_title _("Labels") - can_admin_label = can?(current_user, :admin_label, @project) - search = params[:search] - subscribed = params[:subscribed] diff --git a/app/views/projects/labels/new.html.haml b/app/views/projects/labels/new.html.haml index 96ce0eba2c624779300817489833778e85a3ac39..38bd610243771b69c0d028de0a7ff154cf756575 100644 --- a/app/views/projects/labels/new.html.haml +++ b/app/views/projects/labels/new.html.haml @@ -1,6 +1,6 @@ -- add_to_breadcrumbs "Labels", project_labels_path(@project) -- breadcrumb_title "New" -- page_title "New Label" +- add_to_breadcrumbs _("Labels"), project_labels_path(@project) +- breadcrumb_title _("New") +- page_title _("New Label") %h3.page-title New Label diff --git a/app/views/projects/merge_requests/conflicts/show.html.haml b/app/views/projects/merge_requests/conflicts/show.html.haml index d933675eac54035c8a9dada8041039497b8601fe..6c23661fb8660caeb92ad6119fb84baabfef9ebb 100644 --- a/app/views/projects/merge_requests/conflicts/show.html.haml +++ b/app/views/projects/merge_requests/conflicts/show.html.haml @@ -1,4 +1,4 @@ -- page_title "Merge Conflicts", "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests" +- page_title _("Merge Conflicts"), "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge Requests") - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') = render "projects/merge_requests/mr_title" diff --git a/app/views/projects/merge_requests/creations/new.html.haml b/app/views/projects/merge_requests/creations/new.html.haml index 0f618826305898389afe09d7eee11b64395a6cdc..ad4980fa57f51889baf36bcfa220dd5ecafd0342 100644 --- a/app/views/projects/merge_requests/creations/new.html.haml +++ b/app/views/projects/merge_requests/creations/new.html.haml @@ -1,6 +1,6 @@ -- add_to_breadcrumbs "Merge Requests", project_merge_requests_path(@project) -- breadcrumb_title "New" -- page_title "New Merge Request" +- add_to_breadcrumbs _("Merge Requests"), project_merge_requests_path(@project) +- breadcrumb_title _("New") +- page_title _("New Merge Request") - if @merge_request.can_be_created && !params[:change_branches] = render 'new_submit' diff --git a/app/views/projects/merge_requests/edit.html.haml b/app/views/projects/merge_requests/edit.html.haml index 318c9d809c1c43d609f69623608edfd4ed90df02..a4bb790ce0b6373541a8868b45a76a39c4c8632f 100644 --- a/app/views/projects/merge_requests/edit.html.haml +++ b/app/views/projects/merge_requests/edit.html.haml @@ -1,4 +1,4 @@ -- page_title "Edit", "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests" +- page_title _("Edit"), "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge Requests") %h3.page-title Edit Merge Request #{@merge_request.to_reference} diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index 4e30f09b9a20205bef48a77248965e0933582fe7..36b1cf0796fa1f1f3784b226c852aaa2c59916b2 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -2,7 +2,7 @@ - merge_project = merge_request_source_project_for_project(@project) - new_merge_request_path = project_new_merge_request_path(merge_project) if merge_project -- page_title "Merge Requests" +- page_title _("Merge Requests") - new_merge_request_email = @project.new_issuable_address(current_user, 'merge_request') = render 'projects/last_push' diff --git a/app/views/projects/merge_requests/invalid.html.haml b/app/views/projects/merge_requests/invalid.html.haml index 749228a9664441b85af92645e2f983de4e1d3013..7b831aa2d01a9f1ff76ea16b0e05ac73002fb7d9 100644 --- a/app/views/projects/merge_requests/invalid.html.haml +++ b/app/views/projects/merge_requests/invalid.html.haml @@ -1,4 +1,4 @@ -- page_title "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests" +- page_title "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge Requests") .merge-request = render "projects/merge_requests/mr_title" diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml index 90bc2504cb4d27930240f7a81f7f58dfe6e7844c..ba97bb81c56b6955b73f643a74886ea3fcefb71f 100644 --- a/app/views/projects/merge_requests/show.html.haml +++ b/app/views/projects/merge_requests/show.html.haml @@ -1,8 +1,8 @@ - @gfm_form = true - @content_class = "limit-container-width" unless fluid_layout -- add_to_breadcrumbs "Merge Requests", project_merge_requests_path(@project) +- add_to_breadcrumbs _("Merge Requests"), project_merge_requests_path(@project) - breadcrumb_title @merge_request.to_reference -- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", "Merge Requests" +- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", _("Merge Requests") - page_description @merge_request.description - page_card_attributes @merge_request.card_attributes - suggest_changes_help_path = help_page_path('user/discussions/index.md', anchor: 'suggest-changes') diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml index 6821453cffa7294a0a170c9a1685739d4adcedc8..b8b4507c80f19f90da9db1bed6fa5e34dd019997 100644 --- a/app/views/projects/network/show.html.haml +++ b/app/views/projects/network/show.html.haml @@ -1,5 +1,5 @@ -- breadcrumb_title "Graph" -- page_title "Graph", @ref +- breadcrumb_title _("Graph") +- page_title _("Graph"), @ref = render "head" %div{ class: container_class } .project-network diff --git a/app/views/projects/no_repo.html.haml b/app/views/projects/no_repo.html.haml index 08772a0188b8e03a7bfae0d0a49e166af00ca919..7748aadf44d22c0a6a590ce5ec69ddbd75bcd271 100644 --- a/app/views/projects/no_repo.html.haml +++ b/app/views/projects/no_repo.html.haml @@ -1,4 +1,5 @@ - breadcrumb_title _("Details") +- page_title _("Details") %h2 %i.fa.fa-warning diff --git a/app/views/projects/pages/show.html.haml b/app/views/projects/pages/show.html.haml index 4b7810ea357527757bbfdf0485470a2fc330453a..fc69b390bdeff6963a11b9987123721a66333c25 100644 --- a/app/views/projects/pages/show.html.haml +++ b/app/views/projects/pages/show.html.haml @@ -1,4 +1,4 @@ -- page_title 'Pages' +- page_title _('Pages') - if @project.pages_enabled? %h3.page-title.with-button diff --git a/app/views/projects/protected_branches/show.html.haml b/app/views/projects/protected_branches/show.html.haml index ffaf118a5e32d60473ea9a309c0ab57d37af8110..06578c9407951fbe8900bacf9c3ca713c82269cb 100644 --- a/app/views/projects/protected_branches/show.html.haml +++ b/app/views/projects/protected_branches/show.html.haml @@ -1,4 +1,4 @@ -- page_title @protected_ref.name, "Protected Branches" +- page_title @protected_ref.name, _("Protected Branches") .row.prepend-top-default.append-bottom-default .col-lg-3 diff --git a/app/views/projects/protected_tags/show.html.haml b/app/views/projects/protected_tags/show.html.haml index 6f4535a0b3f11ebb3ffb85e427cf7f5e850a30be..227aac7758375a8b74d76af66fbc09025e3e1ef9 100644 --- a/app/views/projects/protected_tags/show.html.haml +++ b/app/views/projects/protected_tags/show.html.haml @@ -1,4 +1,4 @@ -- page_title @protected_ref.name, "Protected Tags" +- page_title @protected_ref.name, _("Protected Tags") .row.prepend-top-default.append-bottom-default .col-lg-3 diff --git a/app/views/projects/serverless/functions/index.html.haml b/app/views/projects/serverless/functions/index.html.haml index 2f1da453c0a29a11dc24545bbeceeaba7e4f91e8..b21965915a2c7a4fce4bbb8fa570f7f394586c47 100644 --- a/app/views/projects/serverless/functions/index.html.haml +++ b/app/views/projects/serverless/functions/index.html.haml @@ -1,6 +1,6 @@ - @content_class = "limit-container-width" unless fluid_layout -- breadcrumb_title 'Serverless' -- page_title 'Serverless' +- breadcrumb_title _('Serverless') +- page_title _('Serverless') - status_path = project_serverless_functions_path(@project, format: :json) - clusters_path = project_clusters_path(@project) diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 17bc10af58a288f6331948daccb1717d2d612244..732b0d6c9e1b0634bbaa099e10fa9f6fca3f0280 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -1,4 +1,5 @@ - breadcrumb_title _("Details") +- page_title _("Projects") - @content_class = "limit-container-width" unless fluid_layout = content_for :meta_tags do diff --git a/app/views/projects/tags/releases/edit.html.haml b/app/views/projects/tags/releases/edit.html.haml index a3746808440d36beab9c69f16b87969e4deb5e49..55564808e6eec97ea23cd843997e7da3f66fb0c9 100644 --- a/app/views/projects/tags/releases/edit.html.haml +++ b/app/views/projects/tags/releases/edit.html.haml @@ -1,6 +1,6 @@ -- add_to_breadcrumbs "Tags", project_tags_path(@project) +- add_to_breadcrumbs _("Tags"), project_tags_path(@project) - breadcrumb_title @tag.name -- page_title "Edit", @tag.name, "Tags" +- page_title _("Edit"), @tag.name, _("Tags") .sub-header-block.no-bottom-space .oneline diff --git a/app/views/projects/triggers/edit.html.haml b/app/views/projects/triggers/edit.html.haml index e287f05fe6a7c48248df244a25524d24a6b49eb1..b1bc9b0f900bf54be3a73633f8487123e2b9c68e 100644 --- a/app/views/projects/triggers/edit.html.haml +++ b/app/views/projects/triggers/edit.html.haml @@ -1,4 +1,4 @@ -- page_title "Trigger" +- page_title _("Trigger") .row.prepend-top-default.append-bottom-default .col-lg-12 diff --git a/app/views/shared/runners/show.html.haml b/app/views/shared/runners/show.html.haml index f62eed694d28d4f5ba72b77e65e46307b7c60f09..8a78f12bdd8285c117e00364ab6a8fdadbcacfcc 100644 --- a/app/views/shared/runners/show.html.haml +++ b/app/views/shared/runners/show.html.haml @@ -1,4 +1,4 @@ -- page_title "#{@runner.description} ##{@runner.id}", "Runners" +- page_title "#{@runner.description} ##{@runner.id}", _("Runners") %h3.page-title Runner ##{@runner.id} diff --git a/changelogs/unreleased/217587-ignore-title-description-from-services.yml b/changelogs/unreleased/217587-ignore-title-description-from-services.yml new file mode 100644 index 0000000000000000000000000000000000000000..6602b19e9791cf0a1e6bf7ebbbe7f7d8d279ea26 --- /dev/null +++ b/changelogs/unreleased/217587-ignore-title-description-from-services.yml @@ -0,0 +1,5 @@ +--- +title: Remove the ability to customize the title and description of some integrations (Bugzilla, Custom Issue Tracker, Redmine, and YouTrack). +merge_request: 33298 +author: +type: removed diff --git a/changelogs/unreleased/220232-get-all-jira-projects.yml b/changelogs/unreleased/220232-get-all-jira-projects.yml new file mode 100644 index 0000000000000000000000000000000000000000..b0620305a021add7f3cac85dcf03148e2ea8a048 --- /dev/null +++ b/changelogs/unreleased/220232-get-all-jira-projects.yml @@ -0,0 +1,5 @@ +--- +title: Expose all Jira projects endpoint through a GraphQL +merge_request: 33861 +author: +type: added diff --git a/changelogs/unreleased/dmishunov-editor-lite-extensions.yml b/changelogs/unreleased/dmishunov-editor-lite-extensions.yml new file mode 100644 index 0000000000000000000000000000000000000000..e8eb64bcffedf94438f9093658187ba9ea8496a4 --- /dev/null +++ b/changelogs/unreleased/dmishunov-editor-lite-extensions.yml @@ -0,0 +1,5 @@ +--- +title: Support extensibility for Editor Lite +merge_request: 35008 +author: +type: added diff --git a/changelogs/unreleased/services-usage-7.yml b/changelogs/unreleased/services-usage-7.yml new file mode 100644 index 0000000000000000000000000000000000000000..ca3900f36a3ad60add869251a5794db9bef2f882 --- /dev/null +++ b/changelogs/unreleased/services-usage-7.yml @@ -0,0 +1,5 @@ +--- +title: Add DestroyService for GPG keys and use for deleting GPG keys via API +merge_request: 34935 +author: Rajendra Kadam +type: fixed diff --git a/changelogs/unreleased/vij-raw-snippet-blobs.yml b/changelogs/unreleased/vij-raw-snippet-blobs.yml new file mode 100644 index 0000000000000000000000000000000000000000..0576de8bd33ce1cc32c1f9445149f3febcaef6fe --- /dev/null +++ b/changelogs/unreleased/vij-raw-snippet-blobs.yml @@ -0,0 +1,5 @@ +--- +title: Add new raw snippet blob endpoint +merge_request: 33938 +author: +type: added diff --git a/config/routes/project.rb b/config/routes/project.rb index 78dcc189d5b86a80c9568fb8baee7f00c2112169..d00e0ab1d04daf93bbcba8e4d97839bc40275472 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -313,6 +313,12 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do end end + get '/snippets/:snippet_id/raw/:ref/*path', + to: 'snippets/blobs#raw', + format: false, + as: :snippet_blob_raw, + constraints: { snippet_id: /\d+/ } + draw :issues draw :merge_requests draw :pipelines diff --git a/config/routes/snippets.rb b/config/routes/snippets.rb index ba6da3ac57ea5dbdf970955260177dd95ac658a0..259e88ba7b281ff6250bad4090b13cd85a702a8d 100644 --- a/config/routes/snippets.rb +++ b/config/routes/snippets.rb @@ -17,5 +17,14 @@ resources :snippets, concerns: :awardable do end end +# Use this /-/ scope for all new snippet routes. +scope path: '-' do + get '/snippets/:snippet_id/raw/:ref/*path', + to: 'snippets/blobs#raw', + as: :snippet_raw, + format: false, + constraints: { snippet_id: /\d+/ } +end + get '/s/:username', to: redirect('users/%{username}/snippets'), constraints: { username: /[a-zA-Z.0-9_\-]+(? Array | Identifiers of the vulnerability. | | `location` | VulnerabilityLocation | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability | +| `primaryIdentifier` | VulnerabilityIdentifier | Primary identifier of the vulnerability. | | `project` | Project | The project on which the vulnerability was found | | `reportType` | VulnerabilityReportType | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION) | +| `scanner` | VulnerabilityScanner | Scanner metadata for the vulnerability. | | `severity` | VulnerabilitySeverity | Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL) | | `state` | VulnerabilityState | State of the vulnerability (DETECTED, DISMISSED, RESOLVED, CONFIRMED) | | `title` | String | Title of the vulnerability | @@ -2024,6 +2027,17 @@ Represents a vulnerability. | `userPermissions` | VulnerabilityPermissions! | Permissions for the current user on the resource | | `vulnerabilityPath` | String | URL to the vulnerability's details page | +## VulnerabilityIdentifier + +Represents a vulnerability identifier. + +| Name | Type | Description | +| --- | ---- | ---------- | +| `externalId` | String | External ID of the vulnerability identifier | +| `externalType` | String | External type of the vulnerability identifier | +| `name` | String | Name of the vulnerability identifier | +| `url` | String | URL of the vulnerability identifier | + ## VulnerabilityIssueLink Represents an issue link of a vulnerability. @@ -2103,6 +2117,15 @@ Check permissions for the current user on a vulnerability | `readVulnerabilityFeedback` | Boolean! | Indicates the user can perform `read_vulnerability_feedback` on this resource | | `updateVulnerabilityFeedback` | Boolean! | Indicates the user can perform `update_vulnerability_feedback` on this resource | +## VulnerabilityScanner + +Represents a vulnerability scanner. + +| Name | Type | Description | +| --- | ---- | ---------- | +| `externalId` | String | External ID of the vulnerability scanner | +| `name` | String | Name of the vulnerability scanner | + ## VulnerabilitySeveritiesCount Represents vulnerability counts by severity diff --git a/doc/api/issues.md b/doc/api/issues.md index f640300e3ae9dbc6d82e7cebaec27c13cc772fbf..9d6bbf7f0e10274aca7040ceb80a15d4c077e1c1 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Issues API -Every API call to issues must be authenticated. - If a user is not a member of a project and the project is private, a `GET` request on that project will result in a `404` status code. @@ -188,6 +186,9 @@ the `weight` parameter: Get a list of a group's issues. +If the group is private, credentials will need to be provided for authorization. +The preferred way to do this, is by using [personal access tokens](../user/profile/personal_access_tokens.md). + ```plaintext GET /groups/:id/issues GET /groups/:id/issues?state=opened @@ -343,6 +344,9 @@ the `weight` parameter: Get a list of a project's issues. +If the project is private, credentials will need to be provided for authorization. +The preferred way to do this, is by using [personal access tokens](../user/profile/personal_access_tokens.md). + ```plaintext GET /projects/:id/issues GET /projects/:id/issues?state=opened @@ -504,6 +508,9 @@ the `weight` parameter: Get a single project issue. +If the project is private or the issue is confidential, credentials will need to be provided for authorization. +The preferred way to do this, is by using [personal access tokens](../user/profile/personal_access_tokens.md). + ```plaintext GET /projects/:id/issues/:issue_iid ``` @@ -1413,6 +1420,9 @@ Example response: ## Get time tracking stats +If the project is private or the issue is confidential, credentials will need to be provided for authorization. +The preferred way to do this, is by using [personal access tokens](../user/profile/personal_access_tokens.md). + ```plaintext GET /projects/:id/issues/:issue_iid/time_stats ``` @@ -1441,6 +1451,9 @@ Example response: Get all the merge requests that are related to the issue. +If the project is private or the issue is confidential, credentials will need to be provided for authorization. +The preferred way to do this, is by using [personal access tokens](../user/profile/personal_access_tokens.md). + ```plaintext GET /projects/:id/issues/:issue_id/related_merge_requests ``` @@ -1597,6 +1610,9 @@ Example response: Get all the merge requests that will close issue when merged. +If the project is private or the issue is confidential, credentials will need to be provided for authorization. +The preferred way to do this, is by using [personal access tokens](../user/profile/personal_access_tokens.md). + ```plaintext GET /projects/:id/issues/:issue_iid/closed_by ``` @@ -1670,6 +1686,9 @@ Example response: ## Participants on issues +If the project is private or the issue is confidential, credentials will need to be provided for authorization. +The preferred way to do this, is by using [personal access tokens](../user/profile/personal_access_tokens.md). + ```plaintext GET /projects/:id/issues/:issue_iid/participants ``` diff --git a/doc/development/sidekiq_style_guide.md b/doc/development/sidekiq_style_guide.md index 7ae3c9e9de230265405edc0de9f54f98238c0b2a..4b3bf91030eaff2a8da56734d627ae7896bf4355 100644 --- a/doc/development/sidekiq_style_guide.md +++ b/doc/development/sidekiq_style_guide.md @@ -401,6 +401,8 @@ default weight, which is 1. ## Worker context +> - [Introduced](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/9) in GitLab 12.8. + To have some more information about workers in the logs, we add [metadata to the jobs in the form of an `ApplicationContext`](logging.md#logging-context-metadata-through-rails-or-grape-requests). @@ -417,27 +419,27 @@ need to do anything. There are however some instances when there would be no context present when the job is scheduled, or the context that is present is -likely to be incorrect. For these instances we've added rubocop-rules +likely to be incorrect. For these instances, we've added Rubocop rules to draw attention and avoid incorrect metadata in our logs. As with most our cops, there are perfectly valid reasons for disabling them. In this case it could be that the context from the request is correct. Or maybe you've specified a context already in a way that -isn't picked up by the cops. In any case, please leave a code-comment +isn't picked up by the cops. In any case, leave a code comment pointing to which context will be used when disabling the cops. -When you do provide objects to the context, please make sure that the -route for namespaces and projects is pre-loaded. This can be done using +When you do provide objects to the context, make sure that the +route for namespaces and projects is pre-loaded. This can be done by using the `.with_route` scope defined on all `Routable`s. -### Cron-Workers +### Cron workers -The context is automatically cleared for workers in the cronjob-queue -(which `include CronjobQueue`), even when scheduling them from +The context is automatically cleared for workers in the Cronjob queue +(`include CronjobQueue`), even when scheduling them from requests. We do this to avoid incorrect metadata when other jobs are -scheduled from the cron-worker. +scheduled from the cron worker. -Cron-Workers themselves run instance wide, so they aren't scoped to +Cron workers themselves run instance wide, so they aren't scoped to users, namespaces, projects, or other resources that should be added to the context. @@ -449,46 +451,46 @@ somewhere within the worker: 1. Wrap the code that schedules jobs in the `with_context` helper: -```ruby - def perform - deletion_cutoff = Gitlab::CurrentSettings - .deletion_adjourned_period.days.ago.to_date - projects = Project.with_route.with_namespace - .aimed_for_deletion(deletion_cutoff) + ```ruby + def perform + deletion_cutoff = Gitlab::CurrentSettings + .deletion_adjourned_period.days.ago.to_date + projects = Project.with_route.with_namespace + .aimed_for_deletion(deletion_cutoff) - projects.find_each(batch_size: 100).with_index do |project, index| - delay = index * INTERVAL + projects.find_each(batch_size: 100).with_index do |project, index| + delay = index * INTERVAL - with_context(project: project) do - AdjournedProjectDeletionWorker.perform_in(delay, project.id) - end - end - end -``` + with_context(project: project) do + AdjournedProjectDeletionWorker.perform_in(delay, project.id) + end + end + end + ``` 1. Use the a batch scheduling method that provides context: -```ruby - def schedule_projects_in_batch(projects) - ProjectImportScheduleWorker.bulk_perform_async_with_contexts( - projects, - arguments_proc: -> (project) { project.id }, - context_proc: -> (project) { { project: project } } - ) - end -``` - -or when scheduling with delays: - -```ruby - diffs.each_batch(of: BATCH_SIZE) do |diffs, index| - DeleteDiffFilesWorker - .bulk_perform_in_with_contexts(index * 5.minutes, - diffs, - arguments_proc: -> (diff) { diff.id }, - context_proc: -> (diff) { { project: diff.merge_request.target_project } }) - end -``` + ```ruby + def schedule_projects_in_batch(projects) + ProjectImportScheduleWorker.bulk_perform_async_with_contexts( + projects, + arguments_proc: -> (project) { project.id }, + context_proc: -> (project) { { project: project } } + ) + end + ``` + + Or, when scheduling with delays: + + ```ruby + diffs.each_batch(of: BATCH_SIZE) do |diffs, index| + DeleteDiffFilesWorker + .bulk_perform_in_with_contexts(index * 5.minutes, + diffs, + arguments_proc: -> (diff) { diff.id }, + context_proc: -> (diff) { { project: diff.merge_request.target_project } }) + end + ``` ### Jobs scheduled in bulk @@ -512,11 +514,11 @@ For example: Each object from the enumerable in the first argument is yielded into 2 blocks: -The `arguments_proc` which needs to return the list of arguments the -job needs to be scheduled with. +- The `arguments_proc` which needs to return the list of arguments the + job needs to be scheduled with. -The `context_proc` which needs to return a hash with the context -information for the job. +- The `context_proc` which needs to return a hash with the context + information for the job. ## Arguments logging diff --git a/doc/user/project/integrations/bugzilla.md b/doc/user/project/integrations/bugzilla.md index de43c504b05afa9f6da5c82ee09f89b46bbab6aa..6d44c56743e00e944eeade814e3faa7edf4bfb39 100644 --- a/doc/user/project/integrations/bugzilla.md +++ b/doc/user/project/integrations/bugzilla.md @@ -6,7 +6,6 @@ in the table below. | Field | Description | | ----- | ----------- | -| `description` | A name for the issue tracker (to differentiate between instances, for example) | | `project_url` | The URL to the project in Bugzilla which is being linked to this GitLab project. Note that the `project_url` requires PRODUCT_NAME to be updated with the product/project name in Bugzilla. | | `issues_url` | The URL to the issue in Bugzilla project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the URL. This ID is used by GitLab as a placeholder to replace the issue number. | | `new_issue_url` | This is the URL to create a new issue in Bugzilla for the project linked to this GitLab project. Note that the `new_issue_url` requires PRODUCT_NAME to be updated with the product/project name in Bugzilla. | diff --git a/doc/user/project/integrations/custom_issue_tracker.md b/doc/user/project/integrations/custom_issue_tracker.md index 4eaf3a0d4b4b4083cd13703975eae8c320943173..7d15ae82b6f6b1d79437d7df1fded1aaeae214e1 100644 --- a/doc/user/project/integrations/custom_issue_tracker.md +++ b/doc/user/project/integrations/custom_issue_tracker.md @@ -11,8 +11,6 @@ To enable the Custom Issue Tracker integration in a project: | Field | Description | | --------------- | ----------- | - | **Title** | A title for the issue tracker (for example, to differentiate between instances). | - | **Description** | A name for the issue tracker (for example, to differentiate between instances). | | **Project URL** | The URL to the project in the custom issue tracker. | | **Issues URL** | The URL to the issue in the issue tracker project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the URL. This ID is used by GitLab as a placeholder to replace the issue number. For example, `https://customissuetracker.com/project-name/:id`. | | **New issue URL** | Currently unused. Will be changed in a future release. | diff --git a/doc/user/project/integrations/redmine.md b/doc/user/project/integrations/redmine.md index 9e1cdf0490c60a7e84b225d49fd1101791e5630a..c92ddf38ad28d25d840d51aa683499a96507a52c 100644 --- a/doc/user/project/integrations/redmine.md +++ b/doc/user/project/integrations/redmine.md @@ -7,7 +7,6 @@ | Field | Description | | ----- | ----------- | - | `description` | A name for the issue tracker (to differentiate between instances, for example) | | `project_url` | The URL to the project in Redmine which is being linked to this GitLab project | | `issues_url` | The URL to the issue in Redmine project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the URL. This ID is used by GitLab as a placeholder to replace the issue number. | | `new_issue_url` | This is the URL to create a new issue in Redmine for the project linked to this GitLab project. **This is currently not being used and will be removed in a future release.** | diff --git a/doc/user/project/integrations/youtrack.md b/doc/user/project/integrations/youtrack.md index 119a53f5c351e839983a22a165b2fb8fd4b79d24..e067ab6071e3345b6b8b6272b5bf75b268fbbca1 100644 --- a/doc/user/project/integrations/youtrack.md +++ b/doc/user/project/integrations/youtrack.md @@ -13,7 +13,6 @@ To enable YouTrack integration in a project: | Field | Description | |:----------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| - | **Description** | Name for the issue tracker (to differentiate between instances, for example). | | **Project URL** | URL to the project in YouTrack which is being linked to this GitLab project. | | **Issues URL** | URL to the issue in YouTrack project that is linked to this GitLab project. Note that the **Issues URL** requires `:id` in the URL. This ID is used by GitLab as a placeholder to replace the issue number. | diff --git a/lib/api/users.rb b/lib/api/users.rb index 85a33c608e566406234cd23f8a3e0268cef30c64..192eeb691ffc31dd557bc5b38d064219cb0a4d0b 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -374,9 +374,10 @@ module API key = user.gpg_keys.find_by(id: params[:key_id]) not_found!('GPG Key') unless key - key.destroy - - no_content! + destroy_conditionally!(key) do |key| + destroy_service = ::GpgKeys::DestroyService.new(current_user) + destroy_service.execute(key) + end end # rubocop: enable CodeReuse/ActiveRecord diff --git a/lib/gitlab/import_export/project/import_export.yml b/lib/gitlab/import_export/project/import_export.yml index f0b733d7e9584e03a29475dd1a046c0bd3843a6a..7d2a26b2d39089f0b4904990c57929bcd41c4aa7 100644 --- a/lib/gitlab/import_export/project/import_export.yml +++ b/lib/gitlab/import_export/project/import_export.yml @@ -262,9 +262,11 @@ excluded_attributes: - :token - :token_encrypted services: + - :description - :inherit_from_id - :instance - :template + - :title error_tracking_setting: - :encrypted_token - :encrypted_token_iv diff --git a/lib/gitlab/suggestions/file_suggestion.rb b/lib/gitlab/suggestions/file_suggestion.rb index 73b9800f0b8ca0f2dfa6cb6e689e35e8894e9352..7805b27902d6c0383144aa0214836b42a5eeda72 100644 --- a/lib/gitlab/suggestions/file_suggestion.rb +++ b/lib/gitlab/suggestions/file_suggestion.rb @@ -7,17 +7,14 @@ module Gitlab SuggestionForDifferentFileError = Class.new(StandardError) - def initialize - @suggestions = [] - end - - def add_suggestion(new_suggestion) - if for_different_file?(new_suggestion) - raise SuggestionForDifferentFileError, - 'Only add suggestions for the same file.' - end + attr_reader :file_path + attr_reader :blob + attr_reader :suggestions - suggestions << new_suggestion + def initialize(file_path, suggestions) + @file_path = file_path + @suggestions = suggestions.sort_by(&:from_line_index) + @blob = suggestions.first&.diff_file&.new_blob end def line_conflict? @@ -30,18 +27,8 @@ module Gitlab @new_content ||= _new_content end - def file_path - @file_path ||= _file_path - end - private - attr_accessor :suggestions - - def blob - first_suggestion&.diff_file&.new_blob - end - def blob_data_lines blob.load_all_data! blob.data.lines @@ -53,31 +40,19 @@ module Gitlab def _new_content current_content.tap do |content| + # NOTE: We need to cater for line number changes when the range is more than one line. + offset = 0 + suggestions.each do |suggestion| - range = line_range(suggestion) + range = line_range(suggestion, offset) content[range] = suggestion.to_content + offset += range.count - 1 end end.join end - def line_range(suggestion) - suggestion.from_line_index..suggestion.to_line_index - end - - def for_different_file?(suggestion) - file_path && file_path != suggestion_file_path(suggestion) - end - - def suggestion_file_path(suggestion) - suggestion&.diff_file&.file_path - end - - def first_suggestion - suggestions.first - end - - def _file_path - suggestion_file_path(first_suggestion) + def line_range(suggestion, offset = 0) + (suggestion.from_line_index - offset)..(suggestion.to_line_index - offset) end def _line_conflict? diff --git a/lib/gitlab/suggestions/suggestion_set.rb b/lib/gitlab/suggestions/suggestion_set.rb index 22abef98bf024f8a7a2d2922787c50cf47db623b..abb05ba56a70b1ea52aa8f08cbc9765b7bdeb0a0 100644 --- a/lib/gitlab/suggestions/suggestion_set.rb +++ b/lib/gitlab/suggestions/suggestion_set.rb @@ -26,10 +26,10 @@ module Gitlab end def actions - @actions ||= suggestions_per_file.map do |file_path, file_suggestion| + @actions ||= suggestions_per_file.map do |file_suggestion| { action: 'update', - file_path: file_path, + file_path: file_suggestion.file_path, content: file_suggestion.new_content } end @@ -50,19 +50,9 @@ module Gitlab end def _suggestions_per_file - suggestions.each_with_object({}) do |suggestion, result| - file_path = suggestion.diff_file.file_path - file_suggestion = result[file_path] ||= FileSuggestion.new - file_suggestion.add_suggestion(suggestion) - end - end - - def file_suggestions - suggestions_per_file.values - end - - def first_file_suggestion - file_suggestions.first + suggestions + .group_by { |suggestion| suggestion.diff_file.file_path } + .map { |file_path, group| FileSuggestion.new(file_path, group) } end def _error_message @@ -72,7 +62,7 @@ module Gitlab return message if message end - has_line_conflict = file_suggestions.any? do |file_suggestion| + has_line_conflict = suggestions_per_file.any? do |file_suggestion| file_suggestion.line_conflict? end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b9e1e25a76922205553b403d23781edcfd9d614e..8e9ed753f09427bee09e06b7d6322c1e5dec064f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1526,6 +1526,9 @@ msgstr "" msgid "Admin Note" msgstr "" +msgid "Admin Notifications" +msgstr "" + msgid "Admin Overview" msgstr "" @@ -3064,6 +3067,9 @@ msgstr "" msgid "Audit Events is a way to keep track of important events that happened in GitLab." msgstr "" +msgid "Audit Log" +msgstr "" + msgid "AuditEvents|(removed)" msgstr "" @@ -3499,9 +3505,15 @@ msgstr "" msgid "Bitbucket Server Import" msgstr "" +msgid "Bitbucket Server import" +msgstr "" + msgid "Bitbucket import" msgstr "" +msgid "Blame" +msgstr "" + msgid "Blocked" msgstr "" @@ -3715,6 +3727,9 @@ msgstr "" msgid "Broadcast Message was successfully updated." msgstr "" +msgid "Broadcast Messages" +msgstr "" + msgid "Browse Directory" msgstr "" @@ -8159,6 +8174,9 @@ msgstr "" msgid "Edit Release" msgstr "" +msgid "Edit Slack integration" +msgstr "" + msgid "Edit Snippet" msgstr "" @@ -8246,6 +8264,9 @@ msgstr "" msgid "Email" msgstr "" +msgid "Email Notification" +msgstr "" + msgid "Email address" msgstr "" @@ -9965,6 +9986,9 @@ msgstr "" msgid "Filter..." msgstr "" +msgid "Find File" +msgstr "" + msgid "Find by path" msgstr "" @@ -11459,6 +11483,9 @@ msgstr "" msgid "Groups (%{groups})" msgstr "" +msgid "Groups and projects" +msgstr "" + msgid "Groups can also be nested by creating %{subgroup_docs_link_start}subgroups%{subgroup_docs_link_end}." msgstr "" @@ -11766,6 +11793,9 @@ msgstr "" msgid "ID:" msgstr "" +msgid "IDE" +msgstr "" + msgid "IDE|Allow live previews of JavaScript projects in the Web IDE using CodeSandbox Live Preview." msgstr "" @@ -12221,6 +12251,9 @@ msgid_plural "Instances" msgstr[0] "" msgstr[1] "" +msgid "Instance Configuration" +msgstr "" + msgid "Instance Statistics visibility" msgstr "" @@ -12821,6 +12854,9 @@ msgstr "" msgid "Keep divergent refs" msgstr "" +msgid "Kerberos access denied" +msgstr "" + msgid "Key" msgstr "" @@ -12836,6 +12872,9 @@ msgstr "" msgid "Keyboard shortcuts" msgstr "" +msgid "Keys" +msgstr "" + msgid "Ki" msgstr "" @@ -12878,6 +12917,9 @@ msgstr "" msgid "LDAP" msgstr "" +msgid "LDAP Synchronization" +msgstr "" + msgid "LDAP settings" msgstr "" @@ -13616,6 +13658,9 @@ msgstr "" msgid "Manifest file import" msgstr "" +msgid "Manifest import" +msgstr "" + msgid "Manual job" msgstr "" @@ -13859,6 +13904,9 @@ msgstr "" msgid "Merge (when the pipeline succeeds)" msgstr "" +msgid "Merge Conflicts" +msgstr "" + msgid "Merge Request" msgstr "" @@ -14778,9 +14826,18 @@ msgstr "" msgid "New Application" msgstr "" +msgid "New Branch" +msgstr "" + +msgid "New Deploy Key" +msgstr "" + msgid "New Environment" msgstr "" +msgid "New File" +msgstr "" + msgid "New Geo Node" msgstr "" @@ -14807,6 +14864,9 @@ msgstr "" msgid "New Label" msgstr "" +msgid "New Merge Request" +msgstr "" + msgid "New Milestone" msgstr "" @@ -14825,6 +14885,9 @@ msgstr "" msgid "New Snippet" msgstr "" +msgid "New User" +msgstr "" + msgid "New branch" msgstr "" @@ -18169,6 +18232,9 @@ msgstr "" msgid "Protected Branch" msgstr "" +msgid "Protected Branches" +msgstr "" + msgid "Protected Environment" msgstr "" @@ -18181,6 +18247,9 @@ msgstr "" msgid "Protected Tag" msgstr "" +msgid "Protected Tags" +msgstr "" + msgid "Protected branches" msgstr "" @@ -19084,6 +19153,9 @@ msgstr "" msgid "Request Headers" msgstr "" +msgid "Request details" +msgstr "" + msgid "Request parameter %{param} is missing." msgstr "" @@ -24101,6 +24173,9 @@ msgstr "" msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details." msgstr "" +msgid "UI Development Kit" +msgstr "" + msgid "URL" msgstr "" @@ -24458,6 +24533,9 @@ msgstr "" msgid "Upload CSV file" msgstr "" +msgid "Upload License" +msgstr "" + msgid "Upload New File" msgstr "" diff --git a/package.json b/package.json index 02a67664a11339fad28e9b630903a378e4d248d2..0cd75c89f428000f92ddd90e7943aab4eda418ef 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@babel/preset-env": "^7.10.1", "@gitlab/at.js": "1.5.5", "@gitlab/svgs": "1.140.0", - "@gitlab/ui": "17.1.0", + "@gitlab/ui": "17.2.0", "@gitlab/visual-review-tools": "1.6.1", "@rails/actioncable": "^6.0.3-1", "@sentry/browser": "^5.10.2", diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index bcd1a53bd47e0d34b8a322166389c68cdb4591e9..72076fbecf95fd41a6d869e9d7450252c383ea27 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -237,7 +237,7 @@ RSpec.describe Projects::IssuesController do context 'external issue tracker' do let!(:service) do - create(:custom_issue_tracker_service, project: project, title: 'Custom Issue Tracker', new_issue_url: 'http://test.com') + create(:custom_issue_tracker_service, project: project, new_issue_url: 'http://test.com') end before do diff --git a/spec/controllers/projects/snippets/blobs_controller_spec.rb b/spec/controllers/projects/snippets/blobs_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..ca656705e070ea806e760e1779d80187aacd3913 --- /dev/null +++ b/spec/controllers/projects/snippets/blobs_controller_spec.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::Snippets::BlobsController do + using RSpec::Parameterized::TableSyntax + include SnippetHelpers + + let_it_be(:author) { create(:user) } + let_it_be(:developer) { create(:user) } + let_it_be(:other_user) { create(:user) } + + let(:visibility) { :public } + let(:project_visibility) { :public } + let(:project) { create(:project, project_visibility) } + let(:snippet) { create(:project_snippet, visibility, :repository, project: project, author: author) } + + before do + project.add_maintainer(author) + project.add_developer(developer) + end + + describe 'GET #raw' do + let(:filepath) { 'file1' } + let(:ref) { TestEnv::BRANCH_SHA['snippet/single-file'] } + let(:inline) { nil } + + subject do + get(:raw, + params: { + namespace_id: project.namespace, + project_id: project, + snippet_id: snippet, + path: filepath, + ref: ref, + inline: inline + }) + end + + context 'with a snippet without a repository' do + let(:snippet) { create(:project_snippet, visibility, project: project, author: author) } + + it_behaves_like 'raw snippet without repository', :not_found + end + + where(:project_visibility_level, :snippet_visibility_level, :user, :status) do + :public | :public | :author | :ok + :public | :public | :developer | :ok + :public | :public | :other_user | :ok + :public | :public | nil | :ok + + :public | :private | :author | :ok + :public | :private | :developer | :ok + :public | :private | :other_user | :not_found + :public | :private | nil | :not_found + + :private | :public | :author | :ok + :private | :public | :developer | :ok + :private | :public | :other_user | :not_found + :private | :public | nil | :redirect + + :private | :private | :author | :ok + :private | :private | :developer | :ok + :private | :private | :other_user | :not_found + :private | :private | nil | :redirect + end + + with_them do + let(:visibility) { snippet_visibility_level } + let(:project_visibility) { project_visibility_level } + + before do + sign_in_as(user) + + subject + end + + it 'responds with correct status' do + expect(response).to have_gitlab_http_status(status) + end + end + + it_behaves_like 'raw snippet blob' + end +end diff --git a/spec/controllers/snippets/blobs_controller_spec.rb b/spec/controllers/snippets/blobs_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..b9f58587a5813ba15986f50ae85c05eaa2750a26 --- /dev/null +++ b/spec/controllers/snippets/blobs_controller_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Snippets::BlobsController do + using RSpec::Parameterized::TableSyntax + include SnippetHelpers + + describe 'GET #raw' do + let_it_be(:author) { create(:user) } + let_it_be(:other_user) { create(:user) } + + let(:visibility) { :public } + let(:snippet) { create(:personal_snippet, visibility, :repository, author: author) } + let(:filepath) { 'file1' } + let(:ref) { TestEnv::BRANCH_SHA['snippet/single-file'] } + let(:inline) { nil } + + subject do + get(:raw, + params: { + snippet_id: snippet, + path: filepath, + ref: ref, + inline: inline + }) + end + + where(:snippet_visibility_level, :user, :status) do + :public | :author | :ok + :public | :other_user | :ok + :public | nil | :ok + + :private | :author | :ok + :private | :other_user | :not_found + :private | nil | :redirect + end + + with_them do + let(:visibility) { snippet_visibility_level } + + before do + sign_in_as(user) + + subject + end + + it 'responds with correct status' do + expect(response).to have_gitlab_http_status(status) + end + end + + it_behaves_like 'raw snippet blob' + + context 'with a snippet without a repository' do + let(:snippet) { create(:personal_snippet, visibility, author: author) } + + it_behaves_like 'raw snippet without repository', :redirect + end + end +end diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index b78fc63b7ddd33418f8ce89160fb4ca959c458fa..2322babcd531a58b480bf448447061d187604df2 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -174,7 +174,7 @@ RSpec.describe 'Database schema' do IGNORED_JSONB_COLUMNS = { "ApplicationSetting" => %w[repository_storages_weighted], "AlertManagement::Alert" => %w[payload], - "Ci::BuildMetadata" => %w[config_options config_variables secrets], # secrets has an EE-only validator + "Ci::BuildMetadata" => %w[config_options config_variables], "Geo::Event" => %w[payload], "GeoNodeStatus" => %w[status], "Operations::FeatureFlagScope" => %w[strategies], diff --git a/spec/fixtures/gitlab/import_export/corrupted_project_export.tar.gz b/spec/fixtures/gitlab/import_export/corrupted_project_export.tar.gz index cac16cf9cd8c51835ed960bccc68f8cddfdbdc66..e0830c290d11d7aa57cd207072b1c7e388c6242d 100644 Binary files a/spec/fixtures/gitlab/import_export/corrupted_project_export.tar.gz and b/spec/fixtures/gitlab/import_export/corrupted_project_export.tar.gz differ diff --git a/spec/fixtures/gitlab/import_export/lightweight_project_export.tar.gz b/spec/fixtures/gitlab/import_export/lightweight_project_export.tar.gz index c01402954dd5af43b88906c9bedb19b970644a1e..0aa417347784044db90af46e5a5dd74377a5f943 100644 Binary files a/spec/fixtures/gitlab/import_export/lightweight_project_export.tar.gz and b/spec/fixtures/gitlab/import_export/lightweight_project_export.tar.gz differ diff --git a/spec/fixtures/lib/gitlab/import_export/complex/project.json b/spec/fixtures/lib/gitlab/import_export/complex/project.json index 0785da9c1bf4e20a80e0a80d73daecfc2dc5e722..f6a6671b7f12dad950e9fb60f5504ea55eadc887 100644 --- a/spec/fixtures/lib/gitlab/import_export/complex/project.json +++ b/spec/fixtures/lib/gitlab/import_export/complex/project.json @@ -7010,7 +7010,6 @@ "services": [ { "id": 101, - "title": "YouTrack", "project_id": 5, "created_at": "2016-06-14T15:01:51.327Z", "updated_at": "2016-06-14T15:01:51.327Z", @@ -7030,7 +7029,6 @@ }, { "id": 100, - "title": "JetBrains TeamCity CI", "project_id": 5, "created_at": "2016-06-14T15:01:51.315Z", "updated_at": "2016-06-14T15:01:51.315Z", @@ -7050,7 +7048,6 @@ }, { "id": 99, - "title": "Slack", "project_id": 5, "created_at": "2016-06-14T15:01:51.303Z", "updated_at": "2016-06-14T15:01:51.303Z", @@ -7072,7 +7069,6 @@ }, { "id": 98, - "title": "Redmine", "project_id": 5, "created_at": "2016-06-14T15:01:51.289Z", "updated_at": "2016-06-14T15:01:51.289Z", @@ -7092,7 +7088,6 @@ }, { "id": 97, - "title": "Pushover", "project_id": 5, "created_at": "2016-06-14T15:01:51.277Z", "updated_at": "2016-06-14T15:01:51.277Z", @@ -7112,7 +7107,6 @@ }, { "id": 96, - "title": "PivotalTracker", "project_id": 5, "created_at": "2016-06-14T15:01:51.267Z", "updated_at": "2016-06-14T15:01:51.267Z", @@ -7132,7 +7126,6 @@ }, { "id": 95, - "title": "Jira", "project_id": 5, "created_at": "2016-06-14T15:01:51.255Z", "updated_at": "2016-06-14T15:01:51.255Z", @@ -7155,7 +7148,6 @@ }, { "id": 94, - "title": "Irker (IRC gateway)", "project_id": 5, "created_at": "2016-06-14T15:01:51.232Z", "updated_at": "2016-06-14T15:01:51.232Z", @@ -7175,7 +7167,6 @@ }, { "id": 93, - "title": "HipChat", "project_id": 5, "created_at": "2016-06-14T15:01:51.219Z", "updated_at": "2016-06-14T15:01:51.219Z", @@ -7197,7 +7188,6 @@ }, { "id": 91, - "title": "Flowdock", "project_id": 5, "created_at": "2016-06-14T15:01:51.182Z", "updated_at": "2016-06-14T15:01:51.182Z", @@ -7217,7 +7207,6 @@ }, { "id": 90, - "title": "External Wiki", "project_id": 5, "created_at": "2016-06-14T15:01:51.166Z", "updated_at": "2016-06-14T15:01:51.166Z", @@ -7237,7 +7226,6 @@ }, { "id": 89, - "title": "Emails on push", "project_id": 5, "created_at": "2016-06-14T15:01:51.153Z", "updated_at": "2016-06-14T15:01:51.153Z", @@ -7257,7 +7245,6 @@ }, { "id": 88, - "title": "Drone CI", "project_id": 5, "created_at": "2016-06-14T15:01:51.139Z", "updated_at": "2016-06-14T15:01:51.139Z", @@ -7277,7 +7264,6 @@ }, { "id": 87, - "title": "Custom Issue Tracker", "project_id": 5, "created_at": "2016-06-14T15:01:51.125Z", "updated_at": "2016-06-14T15:01:51.125Z", @@ -7297,7 +7283,6 @@ }, { "id": 86, - "title": "Campfire", "project_id": 5, "created_at": "2016-06-14T15:01:51.113Z", "updated_at": "2016-06-14T15:01:51.113Z", @@ -7317,7 +7302,6 @@ }, { "id": 84, - "title": "Buildkite", "project_id": 5, "created_at": "2016-06-14T15:01:51.080Z", "updated_at": "2016-06-14T15:01:51.080Z", @@ -7337,7 +7321,6 @@ }, { "id": 83, - "title": "Atlassian Bamboo CI", "project_id": 5, "created_at": "2016-06-14T15:01:51.067Z", "updated_at": "2016-06-14T15:01:51.067Z", @@ -7357,7 +7340,6 @@ }, { "id": 82, - "title": "Assembla", "project_id": 5, "created_at": "2016-06-14T15:01:51.047Z", "updated_at": "2016-06-14T15:01:51.047Z", @@ -7377,7 +7359,6 @@ }, { "id": 81, - "title": "Asana", "project_id": 5, "created_at": "2016-06-14T15:01:51.031Z", "updated_at": "2016-06-14T15:01:51.031Z", diff --git a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/services.ndjson b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/services.ndjson index 6d6afd3af0b7f264bf20a08d518ea68f396f1b72..e5d39512255323ce2d5dfd03a6ff2a0f113db3bc 100644 --- a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/services.ndjson +++ b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/services.ndjson @@ -1,19 +1,19 @@ -{"id":101,"title":"YouTrack","project_id":5,"created_at":"2016-06-14T15:01:51.327Z","updated_at":"2016-06-14T15:01:51.327Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"YoutrackService","category":"issue_tracker","default":false,"wiki_page_events":true} -{"id":100,"title":"JetBrains TeamCity CI","project_id":5,"created_at":"2016-06-14T15:01:51.315Z","updated_at":"2016-06-14T15:01:51.315Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"TeamcityService","category":"ci","default":false,"wiki_page_events":true} -{"id":99,"title":"Slack","project_id":5,"created_at":"2016-06-14T15:01:51.303Z","updated_at":"2016-06-14T15:01:51.303Z","active":false,"properties":{"notify_only_broken_pipelines":true},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"pipeline_events":true,"type":"SlackService","category":"common","default":false,"wiki_page_events":true} -{"id":98,"title":"Redmine","project_id":5,"created_at":"2016-06-14T15:01:51.289Z","updated_at":"2016-06-14T15:01:51.289Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"RedmineService","category":"issue_tracker","default":false,"wiki_page_events":true} -{"id":97,"title":"Pushover","project_id":5,"created_at":"2016-06-14T15:01:51.277Z","updated_at":"2016-06-14T15:01:51.277Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"PushoverService","category":"common","default":false,"wiki_page_events":true} -{"id":96,"title":"PivotalTracker","project_id":5,"created_at":"2016-06-14T15:01:51.267Z","updated_at":"2016-06-14T15:01:51.267Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"PivotalTrackerService","category":"common","default":false,"wiki_page_events":true} -{"id":95,"title":"Jira","project_id":5,"created_at":"2016-06-14T15:01:51.255Z","updated_at":"2016-06-14T15:01:51.255Z","active":false,"properties":{"api_url":"","jira_issue_transition_id":"2"},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"JiraService","category":"issue_tracker","default":false,"wiki_page_events":true} -{"id":94,"title":"Irker (IRC gateway)","project_id":5,"created_at":"2016-06-14T15:01:51.232Z","updated_at":"2016-06-14T15:01:51.232Z","active":true,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"IrkerService","category":"common","default":false,"wiki_page_events":true} -{"id":93,"title":"HipChat","project_id":5,"created_at":"2016-06-14T15:01:51.219Z","updated_at":"2016-06-14T15:01:51.219Z","active":false,"properties":{"notify_only_broken_pipelines":true},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"pipeline_events":true,"type":"HipchatService","category":"common","default":false,"wiki_page_events":true} -{"id":91,"title":"Flowdock","project_id":5,"created_at":"2016-06-14T15:01:51.182Z","updated_at":"2016-06-14T15:01:51.182Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"FlowdockService","category":"common","default":false,"wiki_page_events":true} -{"id":90,"title":"External Wiki","project_id":5,"created_at":"2016-06-14T15:01:51.166Z","updated_at":"2016-06-14T15:01:51.166Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"ExternalWikiService","category":"common","default":false,"wiki_page_events":true} -{"id":89,"title":"Emails on push","project_id":5,"created_at":"2016-06-14T15:01:51.153Z","updated_at":"2016-06-14T15:01:51.153Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"EmailsOnPushService","category":"common","default":false,"wiki_page_events":true} -{"id":88,"title":"Drone CI","project_id":5,"created_at":"2016-06-14T15:01:51.139Z","updated_at":"2016-06-14T15:01:51.139Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"DroneCiService","category":"ci","default":false,"wiki_page_events":true} -{"id":87,"title":"Custom Issue Tracker","project_id":5,"created_at":"2016-06-14T15:01:51.125Z","updated_at":"2016-06-14T15:01:51.125Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"CustomIssueTrackerService","category":"issue_tracker","default":false,"wiki_page_events":true} -{"id":86,"title":"Campfire","project_id":5,"created_at":"2016-06-14T15:01:51.113Z","updated_at":"2016-06-14T15:01:51.113Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"CampfireService","category":"common","default":false,"wiki_page_events":true} -{"id":84,"title":"Buildkite","project_id":5,"created_at":"2016-06-14T15:01:51.080Z","updated_at":"2016-06-14T15:01:51.080Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"BuildkiteService","category":"ci","default":false,"wiki_page_events":true} -{"id":83,"title":"Atlassian Bamboo CI","project_id":5,"created_at":"2016-06-14T15:01:51.067Z","updated_at":"2016-06-14T15:01:51.067Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"BambooService","category":"ci","default":false,"wiki_page_events":true} -{"id":82,"title":"Assembla","project_id":5,"created_at":"2016-06-14T15:01:51.047Z","updated_at":"2016-06-14T15:01:51.047Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"AssemblaService","category":"common","default":false,"wiki_page_events":true} -{"id":81,"title":"Asana","project_id":5,"created_at":"2016-06-14T15:01:51.031Z","updated_at":"2016-06-14T15:01:51.031Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"AsanaService","category":"common","default":false,"wiki_page_events":true} +{"id":101,"project_id":5,"created_at":"2016-06-14T15:01:51.327Z","updated_at":"2016-06-14T15:01:51.327Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"YoutrackService","category":"issue_tracker","default":false,"wiki_page_events":true} +{"id":100,"project_id":5,"created_at":"2016-06-14T15:01:51.315Z","updated_at":"2016-06-14T15:01:51.315Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"TeamcityService","category":"ci","default":false,"wiki_page_events":true} +{"id":99,"project_id":5,"created_at":"2016-06-14T15:01:51.303Z","updated_at":"2016-06-14T15:01:51.303Z","active":false,"properties":{"notify_only_broken_pipelines":true},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"pipeline_events":true,"type":"SlackService","category":"common","default":false,"wiki_page_events":true} +{"id":98,"project_id":5,"created_at":"2016-06-14T15:01:51.289Z","updated_at":"2016-06-14T15:01:51.289Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"RedmineService","category":"issue_tracker","default":false,"wiki_page_events":true} +{"id":97,"project_id":5,"created_at":"2016-06-14T15:01:51.277Z","updated_at":"2016-06-14T15:01:51.277Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"PushoverService","category":"common","default":false,"wiki_page_events":true} +{"id":96,"project_id":5,"created_at":"2016-06-14T15:01:51.267Z","updated_at":"2016-06-14T15:01:51.267Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"PivotalTrackerService","category":"common","default":false,"wiki_page_events":true} +{"id":95,"project_id":5,"created_at":"2016-06-14T15:01:51.255Z","updated_at":"2016-06-14T15:01:51.255Z","active":false,"properties":{"api_url":"","jira_issue_transition_id":"2"},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"JiraService","category":"issue_tracker","default":false,"wiki_page_events":true} +{"id":94,"project_id":5,"created_at":"2016-06-14T15:01:51.232Z","updated_at":"2016-06-14T15:01:51.232Z","active":true,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"IrkerService","category":"common","default":false,"wiki_page_events":true} +{"id":93,"project_id":5,"created_at":"2016-06-14T15:01:51.219Z","updated_at":"2016-06-14T15:01:51.219Z","active":false,"properties":{"notify_only_broken_pipelines":true},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"pipeline_events":true,"type":"HipchatService","category":"common","default":false,"wiki_page_events":true} +{"id":91,"project_id":5,"created_at":"2016-06-14T15:01:51.182Z","updated_at":"2016-06-14T15:01:51.182Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"FlowdockService","category":"common","default":false,"wiki_page_events":true} +{"id":90,"project_id":5,"created_at":"2016-06-14T15:01:51.166Z","updated_at":"2016-06-14T15:01:51.166Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"ExternalWikiService","category":"common","default":false,"wiki_page_events":true} +{"id":89,"project_id":5,"created_at":"2016-06-14T15:01:51.153Z","updated_at":"2016-06-14T15:01:51.153Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"EmailsOnPushService","category":"common","default":false,"wiki_page_events":true} +{"id":88,"project_id":5,"created_at":"2016-06-14T15:01:51.139Z","updated_at":"2016-06-14T15:01:51.139Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"DroneCiService","category":"ci","default":false,"wiki_page_events":true} +{"id":87,"project_id":5,"created_at":"2016-06-14T15:01:51.125Z","updated_at":"2016-06-14T15:01:51.125Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"CustomIssueTrackerService","category":"issue_tracker","default":false,"wiki_page_events":true} +{"id":86,"project_id":5,"created_at":"2016-06-14T15:01:51.113Z","updated_at":"2016-06-14T15:01:51.113Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"CampfireService","category":"common","default":false,"wiki_page_events":true} +{"id":84,"project_id":5,"created_at":"2016-06-14T15:01:51.080Z","updated_at":"2016-06-14T15:01:51.080Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"BuildkiteService","category":"ci","default":false,"wiki_page_events":true} +{"id":83,"project_id":5,"created_at":"2016-06-14T15:01:51.067Z","updated_at":"2016-06-14T15:01:51.067Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"BambooService","category":"ci","default":false,"wiki_page_events":true} +{"id":82,"project_id":5,"created_at":"2016-06-14T15:01:51.047Z","updated_at":"2016-06-14T15:01:51.047Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"AssemblaService","category":"common","default":false,"wiki_page_events":true} +{"id":81,"project_id":5,"created_at":"2016-06-14T15:01:51.031Z","updated_at":"2016-06-14T15:01:51.031Z","active":false,"properties":{},"template":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"AsanaService","category":"common","default":false,"wiki_page_events":true} diff --git a/spec/fixtures/lib/gitlab/import_export/light/project.json b/spec/fixtures/lib/gitlab/import_export/light/project.json index 326a2cef9ffc15e6de8b6eba3d03c984b9edec5c..cef783163615ba2f1547cd86beaa0896fb9a0623 100644 --- a/spec/fixtures/lib/gitlab/import_export/light/project.json +++ b/spec/fixtures/lib/gitlab/import_export/light/project.json @@ -144,7 +144,6 @@ "services": [ { "id": 100, - "title": "JetBrains TeamCity CI", "project_id": 5, "created_at": "2016-06-14T15:01:51.315Z", "updated_at": "2016-06-14T15:01:51.315Z", @@ -165,7 +164,6 @@ }, { "id": 101, - "title": "Jira", "project_id": 5, "created_at": "2016-06-14T15:01:51.315Z", "updated_at": "2016-06-14T15:01:51.315Z", diff --git a/spec/fixtures/lib/gitlab/import_export/light/tree/project/services.ndjson b/spec/fixtures/lib/gitlab/import_export/light/tree/project/services.ndjson index c5ae6bf4b04ae2b39d0f81a31f9b34445f74fb26..414b68dacd78ef45da8266cbd1e59b3b74eb009f 100644 --- a/spec/fixtures/lib/gitlab/import_export/light/tree/project/services.ndjson +++ b/spec/fixtures/lib/gitlab/import_export/light/tree/project/services.ndjson @@ -1,2 +1,2 @@ -{"id":100,"title":"JetBrains TeamCity CI","project_id":5,"created_at":"2016-06-14T15:01:51.315Z","updated_at":"2016-06-14T15:01:51.315Z","active":false,"properties":{},"template":true,"instance":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"TeamcityService","category":"ci","default":false,"wiki_page_events":true} -{"id":101,"title":"Jira","project_id":5,"created_at":"2016-06-14T15:01:51.315Z","updated_at":"2016-06-14T15:01:51.315Z","active":false,"properties":{},"template":false,"instance":true,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"JiraService","category":"ci","default":false,"wiki_page_events":true} +{"id":100,"project_id":5,"created_at":"2016-06-14T15:01:51.315Z","updated_at":"2016-06-14T15:01:51.315Z","active":false,"properties":{},"template":true,"instance":false,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"TeamcityService","category":"ci","default":false,"wiki_page_events":true} +{"id":101,"project_id":5,"created_at":"2016-06-14T15:01:51.315Z","updated_at":"2016-06-14T15:01:51.315Z","active":false,"properties":{},"template":false,"instance":true,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"job_events":true,"type":"JiraService","category":"ci","default":false,"wiki_page_events":true} diff --git a/spec/frontend/editor/editor_lite_spec.js b/spec/frontend/editor/editor_lite_spec.js index cb07bcf8f2824a6140408d954a8e3cc0190b3ae4..92a136835bf7bb0838f769a66d29f0f62c81f7e3 100644 --- a/spec/frontend/editor/editor_lite_spec.js +++ b/spec/frontend/editor/editor_lite_spec.js @@ -115,6 +115,76 @@ describe('Base editor', () => { }); }); + describe('extensions', () => { + const foo1 = jest.fn(); + const foo2 = jest.fn(); + const bar = jest.fn(); + const MyExt1 = { + foo: foo1, + }; + const MyExt2 = { + bar, + }; + const MyExt3 = { + foo: foo2, + }; + beforeEach(() => { + editor.createInstance({ el: editorEl, blobPath, blobContent }); + }); + + afterEach(() => { + editor.model.dispose(); + }); + + it('is extensible with the extensions', () => { + expect(editor.foo).toBeUndefined(); + + editor.use(MyExt1); + expect(editor.foo).toEqual(foo1); + }); + + it('does not fail if no extensions supplied', () => { + const spy = jest.spyOn(global.console, 'error'); + editor.use(); + + expect(spy).not.toHaveBeenCalled(); + }); + + it('is extensible with multiple extensions', () => { + expect(editor.foo).toBeUndefined(); + expect(editor.bar).toBeUndefined(); + + editor.use([MyExt1, MyExt2]); + + expect(editor.foo).toEqual(foo1); + expect(editor.bar).toEqual(bar); + }); + + it('uses the last definition of a method in case of an overlap', () => { + editor.use([MyExt1, MyExt2, MyExt3]); + expect(editor).toEqual( + expect.objectContaining({ + foo: foo2, + bar, + }), + ); + }); + + it('correctly resolves references withing extensions', () => { + const FunctionExt = { + inst() { + return this.instance; + }, + mod() { + return this.model; + }, + }; + editor.use(FunctionExt); + expect(editor.inst()).toEqual(editor.instance); + expect(editor.mod()).toEqual(editor.model); + }); + }); + describe('languages', () => { it('registers custom languages defined with Monaco', () => { expect(monacoLanguages.getLanguages()).toEqual( diff --git a/spec/frontend/fixtures/services.rb b/spec/frontend/fixtures/services.rb index 0877998cc9d244c0956f62be59476dfde0f3ab99..432303012967a5d4de858dac4beac9f148687efb 100644 --- a/spec/frontend/fixtures/services.rb +++ b/spec/frontend/fixtures/services.rb @@ -8,7 +8,7 @@ RSpec.describe Projects::ServicesController, '(JavaScript fixtures)', type: :con let(:admin) { create(:admin) } let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} let(:project) { create(:project_empty_repo, namespace: namespace, path: 'services-project') } - let!(:service) { create(:custom_issue_tracker_service, project: project, title: 'Custom Issue Tracker') } + let!(:service) { create(:custom_issue_tracker_service, project: project) } render_views diff --git a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb index 364e2aa6ca82c36b5d2e54d76656c835a847972e..156e10e4270197da487b2b40f86c5acf2b9c7259 100644 --- a/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb +++ b/spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb @@ -63,7 +63,7 @@ describe Resolvers::Projects::JiraProjectsResolver do context 'when Jira connection is not valid' do before do - WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/project/search?maxResults=50&query=&startAt=0') + WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/project') .to_raise(JIRA::HTTPError.new(double(message: 'Some failure.'))) end diff --git a/spec/lib/gitlab/suggestions/file_suggestion_spec.rb b/spec/lib/gitlab/suggestions/file_suggestion_spec.rb index 6fbbad017c5a370aaef2d1333274dca6adacd24e..15bb8ae59796e282efda9e9f6910d55563abafb6 100644 --- a/spec/lib/gitlab/suggestions/file_suggestion_spec.rb +++ b/spec/lib/gitlab/suggestions/file_suggestion_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::Suggestions::FileSuggestion do - def create_suggestion(new_line, to_content) + def create_suggestion(new_line, to_content, lines_above = 0, lines_below = 0) position = Gitlab::Diff::Position.new(old_path: file_path, new_path: file_path, old_line: nil, @@ -18,6 +18,8 @@ describe Gitlab::Suggestions::FileSuggestion do create(:suggestion, :content_from_repo, note: diff_note, + lines_above: lines_above, + lines_below: lines_below, to_content: to_content) end @@ -39,27 +41,9 @@ describe Gitlab::Suggestions::FileSuggestion do create_suggestion(15, " *** SUGGESTION 2 ***\n") end - let(:file_suggestion) { described_class.new } + let(:suggestions) { [suggestion1, suggestion2] } - describe '#add_suggestion' do - it 'succeeds when adding a suggestion for the same file as the original' do - file_suggestion.add_suggestion(suggestion1) - - expect { file_suggestion.add_suggestion(suggestion2) }.not_to raise_error - end - - it 'raises an error when adding a suggestion for a different file' do - allow(suggestion2) - .to(receive_message_chain(:diff_file, :file_path) - .and_return('path/to/different/file')) - - file_suggestion.add_suggestion(suggestion1) - - expect { file_suggestion.add_suggestion(suggestion2) }.to( - raise_error(described_class::SuggestionForDifferentFileError) - ) - end - end + let(:file_suggestion) { described_class.new(file_path, suggestions) } describe '#line_conflict' do def stub_suggestions(line_index_spans) @@ -175,67 +159,296 @@ describe Gitlab::Suggestions::FileSuggestion do end describe '#new_content' do - it 'returns a blob with the suggestions applied to it' do - file_suggestion.add_suggestion(suggestion1) - file_suggestion.add_suggestion(suggestion2) + context 'with two suggestions' do + let(:suggestions) { [suggestion1, suggestion2] } - expected_content = <<-CONTENT.strip_heredoc - require 'fileutils' - require 'open3' + it 'returns a blob with the suggestions applied to it' do + expected_content = <<-CONTENT.strip_heredoc + require 'fileutils' + require 'open3' - module Popen - extend self + module Popen + extend self - def popen(cmd, path=nil) - unless cmd.is_a?(Array) - *** SUGGESTION 1 *** + def popen(cmd, path=nil) + unless cmd.is_a?(Array) + *** SUGGESTION 1 *** + end + + path ||= Dir.pwd + + vars = { + *** SUGGESTION 2 *** + } + + options = { + chdir: path + } + + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + + @cmd_output = "" + @cmd_status = 0 + + Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + @cmd_output << stdout.read + @cmd_output << stderr.read + @cmd_status = wait_thr.value.exitstatus + end + + return @cmd_output, @cmd_status end + end + CONTENT - path ||= Dir.pwd + expect(file_suggestion.new_content).to eq(expected_content) + end + end - vars = { - *** SUGGESTION 2 *** - } + context 'when no suggestions have been added' do + let(:suggestions) { [] } - options = { - chdir: path - } + it 'returns an empty string' do + expect(file_suggestion.new_content).to eq('') + end + end + + context 'with multiline suggestions' do + let(:suggestions) { [multi_suggestion1, multi_suggestion2, multi_suggestion3] } + + context 'when the previous suggestion increases the line count' do + let!(:multi_suggestion1) do + create_suggestion(9, " *** SUGGESTION 1 ***\n *** SECOND LINE ***\n *** THIRD LINE ***\n") + end - unless File.directory?(path) - FileUtils.mkdir_p(path) + let!(:multi_suggestion2) do + create_suggestion(15, " *** SUGGESTION 2 ***\n *** SECOND LINE ***\n") + end + + let!(:multi_suggestion3) do + create_suggestion(19, " chdir: *** SUGGESTION 3 ***\n") + end + + it 'returns a blob with the suggestions applied to it' do + expected_content = <<-CONTENT.strip_heredoc + require 'fileutils' + require 'open3' + + module Popen + extend self + + def popen(cmd, path=nil) + unless cmd.is_a?(Array) + *** SUGGESTION 1 *** + *** SECOND LINE *** + *** THIRD LINE *** + end + + path ||= Dir.pwd + + vars = { + *** SUGGESTION 2 *** + *** SECOND LINE *** + } + + options = { + chdir: *** SUGGESTION 3 *** + } + + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + + @cmd_output = "" + @cmd_status = 0 + + Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + @cmd_output << stdout.read + @cmd_output << stderr.read + @cmd_status = wait_thr.value.exitstatus + end + + return @cmd_output, @cmd_status end + end + CONTENT + + expect(file_suggestion.new_content).to eq(expected_content) + end + end - @cmd_output = "" - @cmd_status = 0 + context 'when the previous suggestion decreases and increases the line count' do + let!(:multi_suggestion1) do + create_suggestion(9, " *** SUGGESTION 1 ***\n", 1, 1) + end + + let!(:multi_suggestion2) do + create_suggestion(15, " *** SUGGESTION 2 ***\n *** SECOND LINE ***\n") + end + + let!(:multi_suggestion3) do + create_suggestion(19, " chdir: *** SUGGESTION 3 ***\n") + end + + it 'returns a blob with the suggestions applied to it' do + expected_content = <<-CONTENT.strip_heredoc + require 'fileutils' + require 'open3' + + module Popen + extend self + + def popen(cmd, path=nil) + *** SUGGESTION 1 *** - Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| - @cmd_output << stdout.read - @cmd_output << stderr.read - @cmd_status = wait_thr.value.exitstatus + path ||= Dir.pwd + + vars = { + *** SUGGESTION 2 *** + *** SECOND LINE *** + } + + options = { + chdir: *** SUGGESTION 3 *** + } + + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + + @cmd_output = "" + @cmd_status = 0 + + Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + @cmd_output << stdout.read + @cmd_output << stderr.read + @cmd_status = wait_thr.value.exitstatus + end + + return @cmd_output, @cmd_status end + end + CONTENT + + expect(file_suggestion.new_content).to eq(expected_content) + end + end + + context 'when the previous suggestion replaces with the same number of lines' do + let!(:multi_suggestion1) do + create_suggestion(9, " *** SUGGESTION 1 ***\n *** SECOND LINE ***\n *** THIRD LINE ***\n", 1, 1) + end + + let!(:multi_suggestion2) do + create_suggestion(15, " *** SUGGESTION 2 ***\n") + end + + let!(:multi_suggestion3) do + create_suggestion(19, " chdir: *** SUGGESTION 3 ***\n") + end + + it 'returns a blob with the suggestions applied to it' do + expected_content = <<-CONTENT.strip_heredoc + require 'fileutils' + require 'open3' + + module Popen + extend self + + def popen(cmd, path=nil) + *** SUGGESTION 1 *** + *** SECOND LINE *** + *** THIRD LINE *** + + path ||= Dir.pwd + + vars = { + *** SUGGESTION 2 *** + } + + options = { + chdir: *** SUGGESTION 3 *** + } + + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + + @cmd_output = "" + @cmd_status = 0 + + Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + @cmd_output << stdout.read + @cmd_output << stderr.read + @cmd_status = wait_thr.value.exitstatus + end - return @cmd_output, @cmd_status + return @cmd_output, @cmd_status + end end + CONTENT + + expect(file_suggestion.new_content).to eq(expected_content) end - CONTENT + end - expect(file_suggestion.new_content).to eq(expected_content) - end + context 'when the previous suggestion replaces multiple lines and the suggestions were applied out of order' do + let(:suggestions) { [multi_suggestion1, multi_suggestion3, multi_suggestion2] } - it 'returns an empty string when no suggestions have been added' do - expect(file_suggestion.new_content).to eq('') - end - end + let!(:multi_suggestion1) do + create_suggestion(9, " *** SUGGESTION 1 ***\n *** SECOND LINE ***\n *** THIRD LINE ***\n", 1, 1) + end - describe '#file_path' do - it 'returns the path of the file associated with the suggestions' do - file_suggestion.add_suggestion(suggestion1) + let!(:multi_suggestion3) do + create_suggestion(19, " *** SUGGESTION 3 ***\n", 1, 1) + end - expect(file_suggestion.file_path).to eq(file_path) - end + let!(:multi_suggestion2) do + create_suggestion(15, " *** SUGGESTION 2 ***\n", 1, 1) + end + + it 'returns a blob with the suggestions applied to it' do + expected_content = <<-CONTENT.strip_heredoc + require 'fileutils' + require 'open3' + + module Popen + extend self + + def popen(cmd, path=nil) + *** SUGGESTION 1 *** + *** SECOND LINE *** + *** THIRD LINE *** + + path ||= Dir.pwd + + *** SUGGESTION 2 *** + + *** SUGGESTION 3 *** + + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + + @cmd_output = "" + @cmd_status = 0 - it 'returns nil if no suggestions have been added' do - expect(file_suggestion.file_path).to be(nil) + Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + @cmd_output << stdout.read + @cmd_output << stderr.read + @cmd_status = wait_thr.value.exitstatus + end + + return @cmd_output, @cmd_status + end + end + CONTENT + + expect(file_suggestion.new_content).to eq(expected_content) + end + end end end end diff --git a/spec/lib/gitlab/suggestions/suggestion_set_spec.rb b/spec/lib/gitlab/suggestions/suggestion_set_spec.rb index 8c61e6c42a679507c150c2dec79caab0ead69bd9..b664bb7317641cf3a5eb9df9148a1bc41b87dc03 100644 --- a/spec/lib/gitlab/suggestions/suggestion_set_spec.rb +++ b/spec/lib/gitlab/suggestions/suggestion_set_spec.rb @@ -87,11 +87,10 @@ describe Gitlab::Suggestions::SuggestionSet do it 'returns an array of hashes with proper key/value pairs' do first_action = suggestion_set.actions.first - file_path, file_suggestion = suggestion_set - .send(:suggestions_per_file).first + file_suggestion = suggestion_set.send(:suggestions_per_file).first expect(first_action[:action]).to be('update') - expect(first_action[:file_path]).to eq(file_path) + expect(first_action[:file_path]).to eq(file_suggestion.file_path) expect(first_action[:content]).to eq(file_suggestion.new_content) end end diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb index 588e5872cc85ce2f0d04787f253fe0fbae6baa3d..0f7fa5f8e6032c0424a958f33031fb7e1b3068ef 100644 --- a/spec/models/ci/build_metadata_spec.rb +++ b/spec/models/ci/build_metadata_spec.rb @@ -92,4 +92,33 @@ describe Ci::BuildMetadata do end end end + + describe 'validations' do + context 'when attributes are valid' do + it 'returns no errors' do + metadata.secrets = { + DATABASE_PASSWORD: { + vault: { + engine: { name: 'kv-v2', path: 'kv-v2' }, + path: 'production/db', + field: 'password' + } + } + } + + expect(metadata).to be_valid + end + end + + context 'when data is invalid' do + it 'returns errors' do + metadata.secrets = { DATABASE_PASSWORD: { vault: {} } } + + aggregate_failures do + expect(metadata).to be_invalid + expect(metadata.errors.full_messages).to eq(["Secrets must be a valid json schema"]) + end + end + end + end end diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb index ab939e0d2f88566424e95cfca4d8c3ed9f9d40e4..6818db48feed15a0e225ff4e07efcbf77c395705 100644 --- a/spec/models/project_services/bugzilla_service_spec.rb +++ b/spec/models/project_services/bugzilla_service_spec.rb @@ -32,49 +32,4 @@ describe BugzillaService do it { is_expected.not_to validate_presence_of(:new_issue_url) } end end - - context 'overriding properties' do - let(:url) { 'http://bugzilla.example.com' } - let(:access_params) do - { project_url: url, issues_url: url, new_issue_url: url } - end - - # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 - context 'when data are stored in properties' do - let(:properties) { access_params.merge(title: title, description: description) } - let(:service) do - create(:bugzilla_service, :without_properties_callback, properties: properties) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when data are stored in separated fields' do - let(:service) do - create(:bugzilla_service, title: title, description: description, properties: access_params) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when data are stored in both properties and separated fields' do - let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') } - let(:service) do - create(:bugzilla_service, :without_properties_callback, title: title, description: description, properties: properties) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when no title & description are set' do - let(:service) do - create(:bugzilla_service, properties: access_params) - end - - it 'returns default values' do - expect(service.title).to eq('Bugzilla') - expect(service.description).to eq('Bugzilla issue tracker') - end - end - end end diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb index e749ea6eacc001025fd446b2b277c43c3bbce47e..f2232ae8e9ae4fda70437547857a92cd63ef5811 100644 --- a/spec/models/project_services/custom_issue_tracker_service_spec.rb +++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb @@ -31,66 +31,5 @@ describe CustomIssueTrackerService do it { is_expected.not_to validate_presence_of(:issues_url) } it { is_expected.not_to validate_presence_of(:new_issue_url) } end - - context 'title' do - let(:issue_tracker) { described_class.new(properties: {}) } - - it 'sets a default title' do - issue_tracker.title = nil - - expect(issue_tracker.title).to eq('Custom Issue Tracker') - end - - it 'sets the custom title' do - issue_tracker.title = 'test title' - - expect(issue_tracker.title).to eq('test title') - end - end - end - - context 'overriding properties' do - let(:url) { 'http://custom.example.com' } - let(:access_params) do - { project_url: url, issues_url: url, new_issue_url: url } - end - - # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 - context 'when data are stored in properties' do - let(:properties) { access_params.merge(title: title, description: description) } - let(:service) do - create(:custom_issue_tracker_service, :without_properties_callback, properties: properties) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when data are stored in separated fields' do - let(:service) do - create(:custom_issue_tracker_service, title: title, description: description, properties: access_params) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when data are stored in both properties and separated fields' do - let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') } - let(:service) do - create(:custom_issue_tracker_service, :without_properties_callback, title: title, description: description, properties: properties) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when no title & description are set' do - let(:service) do - create(:custom_issue_tracker_service, properties: access_params) - end - - it 'returns default values' do - expect(service.title).to eq('Custom Issue Tracker') - expect(service.description).to eq('Custom issue tracker') - end - end end end diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb index 7f1c6224b7df94e879a0a4ebd9a4fc79755abb89..ba861aefe3cf28ed6c55369ae8278c76c8cc8e78 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -51,49 +51,4 @@ describe GitlabIssueTrackerService do end end end - - context 'overriding properties' do - let(:url) { 'http://gitlab.example.com' } - let(:access_params) do - { project_url: url, issues_url: url, new_issue_url: url } - end - - # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 - context 'when data are stored in properties' do - let(:properties) { access_params.merge(title: title, description: description) } - let(:service) do - create(:gitlab_issue_tracker_service, :without_properties_callback, properties: properties) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when data are stored in separated fields' do - let(:service) do - create(:gitlab_issue_tracker_service, title: title, description: description, properties: access_params) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when data are stored in both properties and separated fields' do - let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') } - let(:service) do - create(:gitlab_issue_tracker_service, :without_properties_callback, title: title, description: description, properties: properties) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when no title & description are set' do - let(:service) do - create(:gitlab_issue_tracker_service, properties: access_params) - end - - it 'returns default values' do - expect(service.title).to eq('GitLab') - expect(service.description).to eq('GitLab issue tracker') - end - end - end end diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 20e85f0fd4b785f79e19121af36029c9201165ba..5e2dd5f3fc93dda7be6c43c559ab64037b612ce4 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -5,8 +5,6 @@ require 'spec_helper' describe JiraService do include AssetsHelpers - let(:title) { 'custom title' } - let(:description) { 'custom description' } let(:url) { 'http://jira.example.com' } let(:api_url) { 'http://api-jira.example.com' } let(:username) { 'jira-username' } @@ -93,7 +91,6 @@ describe JiraService do let(:params) do { project: create(:project), - title: 'custom title', description: 'custom description', url: url, api_url: api_url, username: username, password: password, jira_issue_transition_id: transition_id @@ -106,19 +103,6 @@ describe JiraService do expect(subject.properties).to be_nil end - it 'sets title correctly' do - service = subject - - expect(service.title).to eq('custom title') - end - - it 'sets service data correctly' do - service = subject - - expect(service.title).to eq('custom title') - expect(service.description).to eq('custom description') - end - it 'stores data in data_fields correcty' do service = subject @@ -209,7 +193,6 @@ describe JiraService do end it 'does not reset password if url "changed" to the same url as before' do - service.title = 'aaaaaa' service.url = 'http://jira.example.com' service.save @@ -318,46 +301,32 @@ describe JiraService do # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 context 'when data are stored in properties' do - let(:properties) { data_params.merge(title: title, description: description) } + let(:properties) { data_params } let!(:service) do create(:jira_service, :without_properties_callback, properties: properties.merge(additional: 'something')) end - it_behaves_like 'issue tracker fields' it_behaves_like 'handles jira fields' end context 'when data are stored in separated fields' do let(:service) do - create(:jira_service, data_params.merge(properties: {}, title: title, description: description)) + create(:jira_service, data_params.merge(properties: {})) end - it_behaves_like 'issue tracker fields' it_behaves_like 'handles jira fields' end context 'when data are stored in both properties and separated fields' do - let(:properties) { data_params.merge(title: title, description: description) } + let(:properties) { data_params } let(:service) do create(:jira_service, :without_properties_callback, active: false, properties: properties).tap do |service| create(:jira_tracker_data, data_params.merge(service: service)) end end - it_behaves_like 'issue tracker fields' it_behaves_like 'handles jira fields' end - - context 'when no title & description are set' do - let(:service) do - create(:jira_service, properties: access_params) - end - - it 'returns default values' do - expect(service.title).to eq('Jira') - expect(service.description).to eq(s_('JiraService|Jira issue tracker')) - end - end end describe '#close_issue' do @@ -704,59 +673,6 @@ describe JiraService do end end - describe 'description and title' do - let(:title) { 'Jira One' } - let(:description) { 'Jira One issue tracker' } - let(:properties) do - { - url: 'http://jira.example.com/web', - username: 'mic', - password: 'password', - title: title, - description: description - } - end - - context 'when it is not set' do - it 'default values are returned' do - service = create(:jira_service) - - expect(service.title).to eq('Jira') - expect(service.description).to eq(s_('JiraService|Jira issue tracker')) - end - end - - context 'when it is set in properties' do - it 'values from properties are returned' do - service = create(:jira_service, :without_properties_callback, properties: properties) - - expect(service.title).to eq(title) - expect(service.description).to eq(description) - end - end - - context 'when it is in title & description fields' do - it 'values from title and description fields are returned' do - service = create(:jira_service, title: title, description: description) - - expect(service.title).to eq(title) - expect(service.description).to eq(description) - end - end - - context 'when it is in both properites & title & description fields' do - it 'values from title and description fields are returned' do - title2 = 'Jira 2' - description2 = 'Jira description 2' - - service = create(:jira_service, title: title2, description: description2, properties: properties) - - expect(service.title).to eq(title2) - expect(service.description).to eq(description2) - end - end - end - describe 'project and issue urls' do context 'when gitlab.yml was initialized' do it 'is prepopulated with the settings' do diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb index 6220d7b1faca7c8e66616eed1012d2f891e50527..4024de3850540c11f2a1d18cd18b11ad5187239c 100644 --- a/spec/models/project_services/redmine_service_spec.rb +++ b/spec/models/project_services/redmine_service_spec.rb @@ -50,49 +50,4 @@ describe RedmineService do expect(described_class.reference_pattern.match('#123')[:issue]).to eq('123') end end - - context 'overriding properties' do - let(:url) { 'http://redmine.example.com' } - let(:access_params) do - { project_url: url, issues_url: url, new_issue_url: url } - end - - # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 - context 'when data are stored in properties' do - let(:properties) { access_params.merge(title: title, description: description) } - let(:service) do - create(:redmine_service, :without_properties_callback, properties: properties) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when data are stored in separated fields' do - let(:service) do - create(:redmine_service, title: title, description: description, properties: access_params) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when data are stored in both properties and separated fields' do - let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') } - let(:service) do - create(:redmine_service, :without_properties_callback, title: title, description: description, properties: properties) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when no title & description are set' do - let(:service) do - create(:redmine_service, properties: access_params) - end - - it 'returns default values' do - expect(service.title).to eq('Redmine') - expect(service.description).to eq('Redmine issue tracker') - end - end - end end diff --git a/spec/models/project_services/youtrack_service_spec.rb b/spec/models/project_services/youtrack_service_spec.rb index b8fff635e9948e54623fa6848bf27f10c27cba16..c82a3cc1bcf52b6fc9f00f43bccf8622fc62bbcd 100644 --- a/spec/models/project_services/youtrack_service_spec.rb +++ b/spec/models/project_services/youtrack_service_spec.rb @@ -42,49 +42,4 @@ describe YoutrackService do expect(described_class.reference_pattern.match('yt-123')[:issue]).to eq('yt-123') end end - - context 'overriding properties' do - let(:url) { 'http://youtrack.example.com' } - let(:access_params) do - { project_url: url, issues_url: url, new_issue_url: url } - end - - # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 - context 'when data are stored in properties' do - let(:properties) { access_params.merge(title: title, description: description) } - let(:service) do - create(:youtrack_service, :without_properties_callback, properties: properties) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when data are stored in separated fields' do - let(:service) do - create(:youtrack_service, title: title, description: description, properties: access_params) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when data are stored in both properties and separated fields' do - let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') } - let(:service) do - create(:youtrack_service, :without_properties_callback, title: title, description: description, properties: properties) - end - - it_behaves_like 'issue tracker fields' - end - - context 'when no title & description are set' do - let(:service) do - create(:youtrack_service, properties: access_params) - end - - it 'returns default values' do - expect(service.title).to eq('YouTrack') - expect(service.description).to eq(s_('IssueTracker|YouTrack issue tracker')) - end - end - end end diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index ca6101364aa223a6342e69361c29d48ae3cf3474..8c914c6b74c71544e0690b65b529ac9dc685d91c 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -304,8 +304,6 @@ RSpec.describe Service do end describe 'build issue tracker from an integration' do - let(:title) { 'custom title' } - let(:description) { 'custom description' } let(:url) { 'http://jira.example.com' } let(:api_url) { 'http://api-jira.example.com' } let(:username) { 'jira-username' } @@ -322,8 +320,6 @@ RSpec.describe Service do service = described_class.build_from_integration(project.id, integration) expect(service).to be_active - expect(service.title).to eq(title) - expect(service.description).to eq(description) expect(service.url).to eq(url) expect(service.api_url).to eq(api_url) expect(service.username).to eq(username) @@ -335,7 +331,7 @@ RSpec.describe Service do # this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 context 'when data are stored in properties' do - let(:properties) { data_params.merge(title: title, description: description) } + let(:properties) { data_params } let!(:integration) do create(:jira_service, :without_properties_callback, template: true, properties: properties.merge(additional: 'something')) end @@ -345,14 +341,14 @@ RSpec.describe Service do context 'when data are stored in separated fields' do let(:integration) do - create(:jira_service, :template, data_params.merge(properties: {}, title: title, description: description)) + create(:jira_service, :template, data_params.merge(properties: {})) end it_behaves_like 'service creation from an integration' end context 'when data are stored in both properties and separated fields' do - let(:properties) { data_params.merge(title: title, description: description) } + let(:properties) { data_params } let(:integration) do create(:jira_service, :without_properties_callback, active: true, template: true, properties: properties).tap do |service| create(:jira_tracker_data, data_params.merge(service: service)) @@ -514,7 +510,6 @@ RSpec.describe Service do let(:service) do GitlabIssueTrackerService.create( project: create(:project), - title: 'random title', project_url: 'http://gitlab.example.com' ) end @@ -523,10 +518,6 @@ RSpec.describe Service do expect { service }.not_to raise_error end - it 'sets title correctly' do - expect(service.title).to eq('random title') - end - it 'sets data correctly' do expect(service.data_fields.project_url).to eq('http://gitlab.example.com') end diff --git a/spec/requests/api/graphql/project/jira_projects_spec.rb b/spec/requests/api/graphql/project/jira_projects_spec.rb index d67c89f18c9ef1ddad247ff22a4b801844da8ae6..4d44d55f2def1814c557e62052cae70bd2128b63 100644 --- a/spec/requests/api/graphql/project/jira_projects_spec.rb +++ b/spec/requests/api/graphql/project/jira_projects_spec.rb @@ -80,34 +80,6 @@ describe 'query Jira projects' do it_behaves_like 'fetches first project' end - - context 'with before cursor' do - let(:projects_query) { 'projects(before: "Mg==", first: 1)' } - - it_behaves_like 'fetches first project' - end - - context 'with after cursor' do - let(:projects_query) { 'projects(after: "MA==", first: 1)' } - - it_behaves_like 'fetches first project' - end - end - - context 'with valid but inexistent after cursor' do - let(:projects_query) { 'projects(after: "MTk==")' } - - it 'retuns empty list of jira projects' do - expect(jira_projects.size).to eq(0) - end - end - - context 'with invalid after cursor' do - let(:projects_query) { 'projects(after: "invalid==")' } - - it 'treats the invalid cursor as no cursor and returns list of jira projects' do - expect(jira_projects.size).to eq(2) - end end end end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 7ae382d8aaefec44a742d7f55d961526008f00a1..966d6f7b106860b2146629c27ec3c392d5fa92c4 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -878,4 +878,12 @@ describe 'project routing' do expect(get('/gitlab/gitlabhq/-/design_management/designs/1/c6f00aa50b80887ada30a6fe517670be9f8f9ece/resized_image/small')).to route_to('application#route_not_found', unmatched_route: 'gitlab/gitlabhq/-/design_management/designs/1/c6f00aa50b80887ada30a6fe517670be9f8f9ece/resized_image/small') end end + + describe Projects::Snippets::BlobsController, "routing" do + it "to #raw" do + expect(get('/gitlab/gitlabhq/-/snippets/1/raw/master/lib/version.rb')) + .to route_to('projects/snippets/blobs#raw', namespace_id: 'gitlab', + project_id: 'gitlabhq', snippet_id: '1', ref: 'master', path: 'lib/version.rb') + end + end end diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index 9c3d17f7d8fc724e20f171bcadcec4c29773b89d..5424f67f4453cd5d2fb240fbb4109725463075f7 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -368,3 +368,10 @@ describe AutocompleteController, 'routing' do expect(get("/autocomplete/award_emojis")).to route_to('autocomplete#award_emojis') end end + +describe Snippets::BlobsController, "routing" do + it "to #raw" do + expect(get('/-/snippets/1/raw/master/lib/version.rb')) + .to route_to('snippets/blobs#raw', snippet_id: '1', ref: 'master', path: 'lib/version.rb') + end +end diff --git a/spec/services/gpg_keys/destroy_service_spec.rb b/spec/services/gpg_keys/destroy_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..82c7ab7adaa3dbb170193c34211a7465e5e506d3 --- /dev/null +++ b/spec/services/gpg_keys/destroy_service_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GpgKeys::DestroyService do + let(:user) { create(:user) } + + subject { described_class.new(user) } + + it 'destroys the GPG key' do + gpg_key = create(:gpg_key) + + expect { subject.execute(gpg_key) }.to change(GpgKey, :count).by(-1) + end +end diff --git a/spec/services/jira/requests/projects_spec.rb b/spec/services/jira/requests/projects_spec.rb index f7b9aa7c00ce784797df8ab85c724dda337db511..42d09da138be63403498686abfd7cf471072ceae 100644 --- a/spec/services/jira/requests/projects_spec.rb +++ b/spec/services/jira/requests/projects_spec.rb @@ -32,14 +32,6 @@ describe Jira::Requests::Projects do end context 'with jira_service' do - context 'when limit is invalid' do - let(:params) { { limit: 0 } } - - it 'returns a paylod with no projects returned' do - expect(subject.payload[:projects]).to be_empty - end - end - context 'when validations and params are ok' do let(:client) { double(options: { site: 'https://jira.example.com' }) } @@ -60,7 +52,7 @@ describe Jira::Requests::Projects do context 'when the request does not return any values' do before do - expect(client).to receive(:get).and_return({ 'someKey' => 'value' }) + expect(client).to receive(:get).and_return([]) end it 'returns a paylod with no projects returned' do @@ -74,19 +66,15 @@ describe Jira::Requests::Projects do context 'when the request returns values' do before do - expect(client).to receive(:get).and_return( - { 'values' => %w(project1 project2), 'isLast' => false } - ) - expect(JIRA::Resource::Project).to receive(:build).with(client, 'project1').and_return('jira_project1') - expect(JIRA::Resource::Project).to receive(:build).with(client, 'project2').and_return('jira_project2') + expect(client).to receive(:get).and_return([{ "key" => 'project1' }, { "key" => 'project2' }]) end it 'returns a paylod with jira projets' do payload = subject.payload expect(subject.success?).to be_truthy - expect(payload[:projects]).to eq(%w(jira_project1 jira_project2)) - expect(payload[:is_last]).to be_falsey + expect(payload[:projects].map(&:key)).to eq(%w(project1 project2)) + expect(payload[:is_last]).to be_truthy end end end diff --git a/spec/support/helpers/jira_service_helper.rb b/spec/support/helpers/jira_service_helper.rb index 198bedfe3bc1037cb836ad4a0a22a033798fd603..9072c41fe66685fc1b089cdbcfad1d33a2e7ec49 100644 --- a/spec/support/helpers/jira_service_helper.rb +++ b/spec/support/helpers/jira_service_helper.rb @@ -5,14 +5,13 @@ module JiraServiceHelper JIRA_API = JIRA_URL + "/rest/api/2" def jira_service_settings - title = "Jira tracker" url = JIRA_URL username = 'jira-user' password = 'my-secret-password' jira_issue_transition_id = '1' jira_tracker.update( - title: title, url: url, username: username, password: password, + url: url, username: username, password: password, jira_issue_transition_id: jira_issue_transition_id, active: true ) end diff --git a/spec/support/helpers/snippet_helpers.rb b/spec/support/helpers/snippet_helpers.rb new file mode 100644 index 0000000000000000000000000000000000000000..ead18792efb1d7f45799d3e1ac9668101ddb2500 --- /dev/null +++ b/spec/support/helpers/snippet_helpers.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module SnippetHelpers + def sign_in_as(user) + sign_in(public_send(user)) if user + end +end diff --git a/spec/support/shared_contexts/requests/api/graphql/jira_import/jira_projects_context.rb b/spec/support/shared_contexts/requests/api/graphql/jira_import/jira_projects_context.rb index f0722beb3ed4fef16315728931b12242c56f0d22..3125f8ba3159ba4bf675e7ae3fe515bff4175cc2 100644 --- a/spec/support/shared_contexts/requests/api/graphql/jira_import/jira_projects_context.rb +++ b/spec/support/shared_contexts/requests/api/graphql/jira_import/jira_projects_context.rb @@ -74,6 +74,48 @@ shared_context 'jira projects request context' do }' end + let_it_be(:all_jira_projects_json) do + '[{ + "expand": "description,lead,issueTypes,url,projectKeys,permissions,insight", + "self": "https://gitlab-jira.atlassian.net/rest/api/2/project/10000", + "id": "10000", + "key": "EX", + "name": "Example", + "avatarUrls": { + "48x48": "https://gitlab-jira.atlassian.net/secure/projectavatar?pid=10000&avatarId=10425", + "24x24": "https://gitlab-jira.atlassian.net/secure/projectavatar?size=small&s=small&pid=10000&avatarId=10425", + "16x16": "https://gitlab-jira.atlassian.net/secure/projectavatar?size=xsmall&s=xsmall&pid=10000&avatarId=10425", + "32x32": "https://gitlab-jira.atlassian.net/secure/projectavatar?size=medium&s=medium&pid=10000&avatarId=10425" + }, + "projectTypeKey": "software", + "simplified": false, + "style": "classic", + "isPrivate": false, + "properties": { + } + }, + { + "expand": "description,lead,issueTypes,url,projectKeys,permissions,insight", + "self": "https://gitlab-jira.atlassian.net/rest/api/2/project/10001", + "id": "10001", + "key": "ABC", + "name": "Alphabetical", + "avatarUrls": { + "48x48": "https://gitlab-jira.atlassian.net/secure/projectavatar?pid=10001&avatarId=10405", + "24x24": "https://gitlab-jira.atlassian.net/secure/projectavatar?size=small&s=small&pid=10001&avatarId=10405", + "16x16": "https://gitlab-jira.atlassian.net/secure/projectavatar?size=xsmall&s=xsmall&pid=10001&avatarId=10405", + "32x32": "https://gitlab-jira.atlassian.net/secure/projectavatar?size=medium&s=medium&pid=10001&avatarId=10405" + }, + "projectTypeKey": "software", + "simplified": true, + "style": "next-gen", + "isPrivate": false, + "properties": { + }, + "entityId": "14935009-f8aa-481e-94bc-f7251f320b0e", + "uuid": "14935009-f8aa-481e-94bc-f7251f320b0e" + }]' + end let_it_be(:empty_jira_projects_json) do '{ "self": "https://your-domain.atlassian.net/rest/api/2/project/search?startAt=0&maxResults=2", @@ -86,10 +128,32 @@ shared_context 'jira projects request context' do }' end + let(:server_info_json) do + '{ + "baseUrl": "https://gitlab-jira.atlassian.net", + "version": "1001.0.0-SNAPSHOT", + "versionNumbers": [ + 1001, + 0, + 0 + ], + "deploymentType": "Cloud", + "buildNumber": 100128, + "buildDate": "2020-06-03T01:58:44.000-0700", + "serverTime": "2020-06-04T06:15:13.686-0700", + "scmInfo": "e736ab140ddb281c7cf5dcf9062c9ce2c08b3c1c", + "serverTitle": "Jira", + "defaultLocale": { + "locale": "en_US" + } + }' + end + let(:test_url) { "#{url}/rest/api/2/project/search?maxResults=50&query=&startAt=0" } let(:start_at_20_url) { "#{url}/rest/api/2/project/search?maxResults=50&query=&startAt=20" } let(:start_at_1_url) { "#{url}/rest/api/2/project/search?maxResults=50&query=&startAt=1" } let(:max_results_1_url) { "#{url}/rest/api/2/project/search?maxResults=1&query=&startAt=0" } + let(:all_projects_url) { "#{url}/rest/api/2/project" } before do WebMock.stub_request(:get, test_url).with(basic_auth: [username, password]) @@ -100,5 +164,9 @@ shared_context 'jira projects request context' do .to_return(body: jira_projects_json, headers: { "Content-Type": "application/json" }) WebMock.stub_request(:get, max_results_1_url).with(basic_auth: [username, password]) .to_return(body: jira_projects_json, headers: { "Content-Type": "application/json" }) + WebMock.stub_request(:get, all_projects_url).with(basic_auth: [username, password]) + .to_return(body: all_jira_projects_json, headers: { "Content-Type": "application/json" }) + WebMock.stub_request(:get, 'https://jira.example.com/rest/api/2/serverInfo') + .to_return(status: 200, body: server_info_json, headers: {}) end end diff --git a/spec/support/shared_examples/controllers/snippet_blob_shared_examples.rb b/spec/support/shared_examples/controllers/snippet_blob_shared_examples.rb new file mode 100644 index 0000000000000000000000000000000000000000..c3e8f807afb82f460a8c1be165ab2c3ca11559cc --- /dev/null +++ b/spec/support/shared_examples/controllers/snippet_blob_shared_examples.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'raw snippet blob' do + context 'with valid params' do + before do + subject + end + + it 'delivers file with correct Workhorse headers' do + expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8') + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true' + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + end + + it 'responds with status 200' do + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'with invalid file path' do + let(:filepath) { 'doesnotexist' } + + it_behaves_like 'returning response status', :not_found + end + + context 'with invalid ref' do + let(:ref) { 'doesnotexist' } + + it_behaves_like 'returning response status', :not_found + end + + it_behaves_like 'content disposition headers' +end + +RSpec.shared_examples 'raw snippet without repository' do |unauthorized_status| + context 'when authorized' do + it 'returns a 422' do + subject + + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end + + context 'when unauthorized' do + let(:visibility) { :private } + + it_behaves_like 'returning response status', unauthorized_status + end +end diff --git a/spec/support/shared_examples/models/services_fields_shared_examples.rb b/spec/support/shared_examples/models/services_fields_shared_examples.rb deleted file mode 100644 index cb36f74460d2a38cb7d1dfe15d65ee490fc56e0e..0000000000000000000000000000000000000000 --- a/spec/support/shared_examples/models/services_fields_shared_examples.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -RSpec.shared_examples 'issue tracker fields' do - let(:title) { 'custom title' } - let(:description) { 'custom description' } - let(:url) { 'http://issue_tracker.example.com' } - - context 'when data are stored in the properties' do - describe '#update' do - before do - service.update(title: 'new_title', description: 'new description') - end - - it 'removes title and description from properties' do - expect(service.reload.properties).not_to include('title', 'description') - end - - it 'stores title & description in services table' do - expect(service.read_attribute(:title)).to eq('new_title') - expect(service.read_attribute(:description)).to eq('new description') - end - end - - describe 'reading fields' do - it 'returns correct values' do - expect(service.title).to eq(title) - expect(service.description).to eq(description) - end - end - end -end diff --git a/yarn.lock b/yarn.lock index 6b482aa33a277d3c0fc53f650803f9de2b40ff49..c5a68e51a1ea801744dd1a4380174914c7539fa1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -840,10 +840,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.140.0.tgz#593f1f65b0df57c3399fcfb9f472f59aa64da074" integrity sha512-6gANJGi2QkpvOgFTMcY3SIwEqhO69i6R3jU4BSskkVziwDdAWxGonln22a4Iu//Iv0NrsFDpAA0jIVfnJzw0iA== -"@gitlab/ui@17.1.0": - version "17.1.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-17.1.0.tgz#522912caee7689a0fde1e58cd6d4e4163e39ca7f" - integrity sha512-KruPE0I4qU4LP+pPIzhCY0xbNDcB7gUHaXMO1we2ssK9lc+NJxeLt9gr/ctOX1/Rzgau93+i9QvekeNg0wvqGA== +"@gitlab/ui@17.2.0": + version "17.2.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-17.2.0.tgz#c4bca963c987f21131be0a650bca47b3708714f2" + integrity sha512-pCzHoA41ggaPjN7612I5MxXq370Utlml9joUuo92BAXQk5XslAJQOFkdmyF/E89qaT7vgWurVAfPylqnSc5LrA== dependencies: "@babel/standalone" "^7.0.0" "@gitlab/vue-toasted" "^1.3.0"