Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-22 15:08:47 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-22 15:08:47 +0300
commit6046a605fdbb6d180861c978d17fe3516b2e7507 (patch)
tree42cc483042b341475ba14d8fbfad6432a15327f4
parent5956978e1d2aa2b5b35c2d79f67f6b9706b8ec4e (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue4
-rw-r--r--app/assets/javascripts/editor/editor_lite.js5
-rw-r--r--app/assets/javascripts/snippets/fragments/project.fragment.graphql4
-rw-r--r--app/assets/javascripts/snippets/queries/snippet.query.graphql2
-rw-r--r--app/controllers/concerns/service_params.rb2
-rw-r--r--app/controllers/concerns/snippets/blobs_actions.rb53
-rw-r--r--app/controllers/concerns/snippets/send_blob.rb22
-rw-r--r--app/controllers/concerns/snippets_actions.rb18
-rw-r--r--app/controllers/projects/snippets/blobs_controller.rb5
-rw-r--r--app/controllers/projects/snippets_controller.rb4
-rw-r--r--app/controllers/snippets/blobs_controller.rb7
-rw-r--r--app/graphql/resolvers/projects/jira_projects_resolver.rb42
-rw-r--r--app/graphql/types/projects/services/jira_service_type.rb2
-rw-r--r--app/models/ci/build_metadata.rb3
-rw-r--r--app/models/project_services/bugzilla_service.rb4
-rw-r--r--app/models/project_services/custom_issue_tracker_service.rb6
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb4
-rw-r--r--app/models/project_services/issue_tracker_service.rb32
-rw-r--r--app/models/project_services/jira_service.rb6
-rw-r--r--app/models/project_services/redmine_service.rb4
-rw-r--r--app/models/project_services/youtrack_service.rb5
-rw-r--r--app/models/service.rb3
-rw-r--r--app/services/gpg_keys/destroy_service.rb9
-rw-r--r--app/services/jira/requests/base.rb12
-rw-r--r--app/services/jira/requests/projects.rb15
-rw-r--r--app/views/admin/appearances/show.html.haml2
-rw-r--r--app/views/admin/applications/edit.html.haml4
-rw-r--r--app/views/admin/applications/index.html.haml2
-rw-r--r--app/views/admin/applications/new.html.haml4
-rw-r--r--app/views/admin/applications/show.html.haml2
-rw-r--r--app/views/admin/background_jobs/show.html.haml2
-rw-r--r--app/views/admin/broadcast_messages/edit.html.haml4
-rw-r--r--app/views/admin/broadcast_messages/index.html.haml4
-rw-r--r--app/views/admin/dashboard/index.html.haml3
-rw-r--r--app/views/admin/deploy_keys/new.html.haml2
-rw-r--r--app/views/admin/gitaly_servers/index.html.haml1
-rw-r--r--app/views/admin/hook_logs/show.html.haml2
-rw-r--r--app/views/admin/jobs/index.html.haml3
-rw-r--r--app/views/admin/keys/show.html.haml2
-rw-r--r--app/views/admin/projects/show.html.haml4
-rw-r--r--app/views/admin/requests_profiles/index.html.haml2
-rw-r--r--app/views/admin/runners/index.html.haml1
-rw-r--r--app/views/admin/runners/show.html.haml1
-rw-r--r--app/views/admin/services/edit.html.haml4
-rw-r--r--app/views/admin/services/index.html.haml2
-rw-r--r--app/views/admin/spam_logs/index.html.haml2
-rw-r--r--app/views/admin/users/edit.html.haml2
-rw-r--r--app/views/admin/users/index.html.haml2
-rw-r--r--app/views/admin/users/keys.html.haml4
-rw-r--r--app/views/admin/users/new.html.haml2
-rw-r--r--app/views/admin/users/projects.html.haml4
-rw-r--r--app/views/admin/users/show.html.haml4
-rw-r--r--app/views/dashboard/activity.html.haml4
-rw-r--r--app/views/dashboard/groups/index.html.haml4
-rw-r--r--app/views/dashboard/milestones/index.html.haml4
-rw-r--r--app/views/dashboard/projects/index.html.haml4
-rw-r--r--app/views/dashboard/snippets/index.html.haml4
-rw-r--r--app/views/dashboard/todos/index.html.haml4
-rw-r--r--app/views/devise/registrations/new.html.haml2
-rw-r--r--app/views/devise/sessions/new.html.haml2
-rw-r--r--app/views/explore/snippets/index.html.haml4
-rw-r--r--app/views/groups/activity.html.haml2
-rw-r--r--app/views/groups/edit.html.haml1
-rw-r--r--app/views/groups/issues.html.haml2
-rw-r--r--app/views/groups/labels/edit.html.haml2
-rw-r--r--app/views/groups/labels/index.html.haml2
-rw-r--r--app/views/groups/merge_requests.html.haml2
-rw-r--r--app/views/groups/milestones/index.html.haml2
-rw-r--r--app/views/groups/projects.html.haml3
-rw-r--r--app/views/groups/settings/ci_cd/show.html.haml4
-rw-r--r--app/views/groups/show.html.haml1
-rw-r--r--app/views/help/instance_configuration.html.haml2
-rw-r--r--app/views/help/ui.html.haml2
-rw-r--r--app/views/ide/_show.html.haml2
-rw-r--r--app/views/import/bitbucket_server/new.html.haml2
-rw-r--r--app/views/import/bitbucket_server/status.html.haml4
-rw-r--r--app/views/import/manifest/new.html.haml4
-rw-r--r--app/views/import/manifest/status.html.haml4
-rw-r--r--app/views/instance_statistics/cohorts/index.html.haml1
-rw-r--r--app/views/layouts/header/_new_dropdown.haml1
-rw-r--r--app/views/layouts/snippets.html.haml1
-rw-r--r--app/views/profiles/show.html.haml1
-rw-r--r--app/views/projects/artifacts/browse.html.haml2
-rw-r--r--app/views/projects/artifacts/file.html.haml2
-rw-r--r--app/views/projects/blame/show.html.haml2
-rw-r--r--app/views/projects/blob/edit.html.haml4
-rw-r--r--app/views/projects/blob/new.html.haml4
-rw-r--r--app/views/projects/branches/new.html.haml2
-rw-r--r--app/views/projects/compare/index.html.haml4
-rw-r--r--app/views/projects/cycle_analytics/show.html.haml2
-rw-r--r--app/views/projects/deploy_keys/edit.html.haml2
-rw-r--r--app/views/projects/empty.html.haml1
-rw-r--r--app/views/projects/find_file/show.html.haml2
-rw-r--r--app/views/projects/imports/new.html.haml2
-rw-r--r--app/views/projects/issues/edit.html.haml2
-rw-r--r--app/views/projects/issues/index.html.haml2
-rw-r--r--app/views/projects/jobs/index.html.haml2
-rw-r--r--app/views/projects/jobs/terminal.html.haml6
-rw-r--r--app/views/projects/labels/edit.html.haml6
-rw-r--r--app/views/projects/labels/index.html.haml2
-rw-r--r--app/views/projects/labels/new.html.haml6
-rw-r--r--app/views/projects/merge_requests/conflicts/show.html.haml2
-rw-r--r--app/views/projects/merge_requests/creations/new.html.haml6
-rw-r--r--app/views/projects/merge_requests/edit.html.haml2
-rw-r--r--app/views/projects/merge_requests/index.html.haml2
-rw-r--r--app/views/projects/merge_requests/invalid.html.haml2
-rw-r--r--app/views/projects/merge_requests/show.html.haml4
-rw-r--r--app/views/projects/network/show.html.haml4
-rw-r--r--app/views/projects/no_repo.html.haml1
-rw-r--r--app/views/projects/pages/show.html.haml2
-rw-r--r--app/views/projects/protected_branches/show.html.haml2
-rw-r--r--app/views/projects/protected_tags/show.html.haml2
-rw-r--r--app/views/projects/serverless/functions/index.html.haml4
-rw-r--r--app/views/projects/show.html.haml1
-rw-r--r--app/views/projects/tags/releases/edit.html.haml4
-rw-r--r--app/views/projects/triggers/edit.html.haml2
-rw-r--r--app/views/shared/runners/show.html.haml2
-rw-r--r--changelogs/unreleased/217587-ignore-title-description-from-services.yml5
-rw-r--r--changelogs/unreleased/220232-get-all-jira-projects.yml5
-rw-r--r--changelogs/unreleased/dmishunov-editor-lite-extensions.yml5
-rw-r--r--changelogs/unreleased/services-usage-7.yml5
-rw-r--r--changelogs/unreleased/vij-raw-snippet-blobs.yml5
-rw-r--r--config/routes/project.rb6
-rw-r--r--config/routes/snippets.rb9
-rw-r--r--doc/administration/high_availability/nfs.md8
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql57
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json166
-rw-r--r--doc/api/graphql/reference/index.md25
-rw-r--r--doc/api/issues.md23
-rw-r--r--doc/development/sidekiq_style_guide.md98
-rw-r--r--doc/user/project/integrations/bugzilla.md1
-rw-r--r--doc/user/project/integrations/custom_issue_tracker.md2
-rw-r--r--doc/user/project/integrations/redmine.md1
-rw-r--r--doc/user/project/integrations/youtrack.md1
-rw-r--r--lib/api/users.rb7
-rw-r--r--lib/gitlab/import_export/project/import_export.yml2
-rw-r--r--lib/gitlab/suggestions/file_suggestion.rb53
-rw-r--r--lib/gitlab/suggestions/suggestion_set.rb22
-rw-r--r--locale/gitlab.pot78
-rw-r--r--package.json2
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb2
-rw-r--r--spec/controllers/projects/snippets/blobs_controller_spec.rb85
-rw-r--r--spec/controllers/snippets/blobs_controller_spec.rb61
-rw-r--r--spec/db/schema_spec.rb2
-rw-r--r--spec/fixtures/gitlab/import_export/corrupted_project_export.tar.gzbin4352 -> 3973 bytes
-rw-r--r--spec/fixtures/gitlab/import_export/lightweight_project_export.tar.gzbin3837 -> 3778 bytes
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/project.json19
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/tree/project/services.ndjson38
-rw-r--r--spec/fixtures/lib/gitlab/import_export/light/project.json2
-rw-r--r--spec/fixtures/lib/gitlab/import_export/light/tree/project/services.ndjson4
-rw-r--r--spec/frontend/editor/editor_lite_spec.js70
-rw-r--r--spec/frontend/fixtures/services.rb2
-rw-r--r--spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb2
-rw-r--r--spec/lib/gitlab/suggestions/file_suggestion_spec.rb337
-rw-r--r--spec/lib/gitlab/suggestions/suggestion_set_spec.rb5
-rw-r--r--spec/models/ci/build_metadata_spec.rb29
-rw-r--r--spec/models/project_services/bugzilla_service_spec.rb45
-rw-r--r--spec/models/project_services/custom_issue_tracker_service_spec.rb61
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb45
-rw-r--r--spec/models/project_services/jira_service_spec.rb90
-rw-r--r--spec/models/project_services/redmine_service_spec.rb45
-rw-r--r--spec/models/project_services/youtrack_service_spec.rb45
-rw-r--r--spec/models/service_spec.rb15
-rw-r--r--spec/requests/api/graphql/project/jira_projects_spec.rb28
-rw-r--r--spec/routing/project_routing_spec.rb8
-rw-r--r--spec/routing/routing_spec.rb7
-rw-r--r--spec/services/gpg_keys/destroy_service_spec.rb15
-rw-r--r--spec/services/jira/requests/projects_spec.rb20
-rw-r--r--spec/support/helpers/jira_service_helper.rb3
-rw-r--r--spec/support/helpers/snippet_helpers.rb7
-rw-r--r--spec/support/shared_contexts/requests/api/graphql/jira_import/jira_projects_context.rb68
-rw-r--r--spec/support/shared_examples/controllers/snippet_blob_shared_examples.rb49
-rw-r--r--spec/support/shared_examples/models/services_fields_shared_examples.rb31
-rw-r--r--yarn.lock8
174 files changed, 1463 insertions, 889 deletions
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index 61bbf13aa53..d2110483c1c 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 6db24a1b7ef..551ffbabaef 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 7d65789c67b..64bb2315c1b 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 c58a5168ba3..b23ab862439 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 e78fa8f8250..a3e986572ef 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 00000000000..db56ce8f193
--- /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 00000000000..4f432430aaa
--- /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 51fc12398d9..3b8f9722913 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 00000000000..148fc7c96f8
--- /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 5ee6abef804..1bc63fce5fc 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 00000000000..d7c4bbcf8f2
--- /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 a8c3768df41..2b5d04ef39e 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 e81963f752d..8bf85a14cbf 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 c756a9b546a..4094bdb26dc 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 0a498fde95a..4332db3e961 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 dbc42b1b86d..fc58ba27c3d 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 ec28602b5e6..b3f44e040bc 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 f5d6ae10469..694374e9548 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 bb4d35cad22..8c97547f416 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 a4ca0d20669..df78520d65f 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 40203ad692d..7fb3bde44a5 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 04b30930d54..e310ff9abd2 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 00000000000..cecbfe26611
--- /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 7521c7610cb..0934730d10c 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 da464503211..afb3b45fac1 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 ccf6f960cf2..77a08913666 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 13c408914bb..4f737a14e12 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 c3861f335b8..0119cabf1ad 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 346c58877d9..4d4b6b0c994 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 146674a2fac..b39a753d010 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 1001a69b787..bbb47e29bb9 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 8cbc4597e32..569aaa29cc4 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 e7a7ee96508..bca74f71c5c 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 951e5364ad8..3afed99334b 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 9a563a5bc78..f43c1447f09 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 9b24f411a75..0b06f145687 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 86729dbe7bc..e0256e66376 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 f1bdd52b399..32c0a801a1d 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 9ee77c77398..03cc0ae15be 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 f9d42d3f53b..1edfedb00f8 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 efc16bb4d3b..b7a4401d90e 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 59e28a3b244..08d65819476 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 0120d4038b9..0c2b9bab357 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 558fe3ab15d..d13b5a34dac 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 b476c990462..ec343c38470 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 b45d3e4823b..40fbc559d72 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 3b6fd71500d..7d10e839cd6 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 ecbabab3e7f..69df8fa2198 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 103bbb3b063..5f9d11af7c1 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 bfc36ed7373..e5e6790b789 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 e6da81831ab..5a11ee7e836 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 c2ceb7e7cbb..2bc39a23b2d 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 d7306f5932d..1e93613e978 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 d1d8d970b59..9536ff940f5 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 b9be6028b72..a0c1c314a85 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 d2aa07bab22..2e7eab87af3 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 2f0cc76f2e0..68457ab33f7 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 cfc637592d3..9fca580a870 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 9fb5e27b692..fb00e1b4384 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 fd6d8f3f769..c466d2ce936 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 d23c8301b10..bf861e30b3a 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 cb7dab26332..bc75fada937 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 2e58517fdc7..1e04b2761f6 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 1cb1cc45bdb..59432e5f015 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 586b0f6ebfa..fbab4f8a250 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 41c1d3e84b7..ec6694672ae 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 0780fab513b..1828f850d35 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 03407adb57d..89ea0c6c7d9 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 8b01e54474a..c9cf8c5a76c 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 8c9b859e127..366d7dd5afe 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 7e5bf6ddde1..d896b28944e 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 99576d45f76..260566b1441 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 d71650ae50c..5c216ee1ec0 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 b871f0363f3..d0384fd50bc 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 2eac8d0c5a1..18ccad9ca30 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 7523b8f7b1c..c4b30a8c17e 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 df00c4d2179..852f269f2ed 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 3d4abc32b88..e85162ad1b4 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 5333f8b7a1f..771e988e256 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 3cbfb24a868..4bfac76ec5b 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 cde2b467392..6cc53ba3342 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 78fdcdef3c4..f5ea805cf85 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 7abac2d14e4..ff56cb53720 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 808b4acc8f3..1ad70506be4 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 0591c3180ea..a2d6b2e18a9 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 3d84adbc49a..1319c58eb38 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 f9abcffeeb4..2420c4a4bd5 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 af8887b0c39..97e46aaa710 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 02f2b104ce3..93ee1bed809 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 b6c30c680e4..090fc602ebb 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 0ce93eef369..7fa7036245c 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 6b1455acd08..68c2af336b3 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 971107675ab..3b0555908f6 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 bd0ab2c19f2..58981ca1556 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 1b7d878c38c..353ff9c1cc2 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 826a62e39d3..cfc423da57a 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 5acb2af08e4..4f537ee8014 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 5439a4b5d5c..01f40543926 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 b7996f0dad1..343900359b4 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 760d81136c6..93ece26357e 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 96ce0eba2c6..38bd6102437 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 d933675eac5..6c23661fb86 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 0f618826305..ad4980fa57f 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 318c9d809c1..a4bb790ce0b 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 4e30f09b9a2..36b1cf0796f 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 749228a9664..7b831aa2d01 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 90bc2504cb4..ba97bb81c56 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 6821453cffa..b8b4507c80f 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 08772a0188b..7748aadf44d 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 4b7810ea357..fc69b390bde 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 ffaf118a5e3..06578c94079 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 6f4535a0b3f..227aac77583 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 2f1da453c0a..b21965915a2 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 17bc10af58a..732b0d6c9e1 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 a3746808440..55564808e6e 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 e287f05fe6a..b1bc9b0f900 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 f62eed694d2..8a78f12bdd8 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 00000000000..6602b19e979
--- /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 00000000000..b0620305a02
--- /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 00000000000..e8eb64bcffe
--- /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 00000000000..ca3900f36a3
--- /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 00000000000..0576de8bd33
--- /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 78dcc189d5b..d00e0ab1d04 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 ba6da3ac57e..259e88ba7b2 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_\-]+(?<!\.atom)/ }
diff --git a/doc/administration/high_availability/nfs.md b/doc/administration/high_availability/nfs.md
index 6511f9bd85d..4d38bc7cc79 100644
--- a/doc/administration/high_availability/nfs.md
+++ b/doc/administration/high_availability/nfs.md
@@ -17,6 +17,14 @@ performance, especially for actions that read or write to Git repositories. See
[Filesystem Performance Benchmarking](../operations/filesystem_benchmarking.md)
for steps to test filesystem performance.
+## Known kernel version incompatibilities
+
+The following kernel versions should NOT be used with GitLab:
+
+|Distribution |Kernel Versions|Affected GitLab versions|Details|
+|-------------|---------------|------------------------|-------|
+|RHEL/CentOS|`3.10.0-1127*`|All prior to GitLab 13.1|[Uploads fail to copy over NFS](https://gitlab.com/gitlab-org/gitlab/-/issues/218999)|
+
## NFS Server features
### Required features
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 8366affc4ef..fce8a85cc07 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -6274,7 +6274,7 @@ type JiraService implements Service {
active: Boolean
"""
- List of Jira projects fetched through Jira REST API
+ List of all Jira projects fetched through Jira REST API
"""
projects(
"""
@@ -13561,6 +13561,11 @@ type Vulnerability {
id: ID!
"""
+ Identifiers of the vulnerability.
+ """
+ identifiers: [VulnerabilityIdentifier!]!
+
+ """
List of issue links related to the vulnerability
"""
issueLinks(
@@ -13596,6 +13601,11 @@ type Vulnerability {
location: VulnerabilityLocation
"""
+ Primary identifier of the vulnerability.
+ """
+ primaryIdentifier: VulnerabilityIdentifier
+
+ """
The project on which the vulnerability was found
"""
project: Project
@@ -13607,6 +13617,11 @@ type Vulnerability {
reportType: VulnerabilityReportType
"""
+ Scanner metadata for the vulnerability.
+ """
+ scanner: VulnerabilityScanner
+
+ """
Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL)
"""
severity: VulnerabilitySeverity
@@ -13673,6 +13688,31 @@ type VulnerabilityEdge {
}
"""
+Represents a vulnerability identifier.
+"""
+type VulnerabilityIdentifier {
+ """
+ External ID of the vulnerability identifier
+ """
+ externalId: String
+
+ """
+ External type of the vulnerability identifier
+ """
+ externalType: String
+
+ """
+ Name of the vulnerability identifier
+ """
+ name: String
+
+ """
+ URL of the vulnerability identifier
+ """
+ url: String
+}
+
+"""
Represents an issue link of a vulnerability.
"""
type VulnerabilityIssueLink {
@@ -13917,6 +13957,21 @@ enum VulnerabilityReportType {
}
"""
+Represents a vulnerability scanner.
+"""
+type VulnerabilityScanner {
+ """
+ External ID of the vulnerability scanner
+ """
+ externalId: String
+
+ """
+ Name of the vulnerability scanner
+ """
+ name: String
+}
+
+"""
Represents vulnerability counts by severity
"""
type VulnerabilitySeveritiesCount {
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index fb755d34468..51f2a571b03 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -17342,7 +17342,7 @@
},
{
"name": "projects",
- "description": "List of Jira projects fetched through Jira REST API",
+ "description": "List of all Jira projects fetched through Jira REST API",
"args": [
{
"name": "name",
@@ -39869,6 +39869,32 @@
"deprecationReason": null
},
{
+ "name": "identifiers",
+ "description": "Identifiers of the vulnerability.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "VulnerabilityIdentifier",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "issueLinks",
"description": "List of issue links related to the vulnerability",
"args": [
@@ -39950,6 +39976,20 @@
"deprecationReason": null
},
{
+ "name": "primaryIdentifier",
+ "description": "Primary identifier of the vulnerability.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "VulnerabilityIdentifier",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "project",
"description": "The project on which the vulnerability was found",
"args": [
@@ -39978,6 +40018,20 @@
"deprecationReason": null
},
{
+ "name": "scanner",
+ "description": "Scanner metadata for the vulnerability.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "VulnerabilityScanner",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "severity",
"description": "Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL)",
"args": [
@@ -40191,6 +40245,75 @@
},
{
"kind": "OBJECT",
+ "name": "VulnerabilityIdentifier",
+ "description": "Represents a vulnerability identifier.",
+ "fields": [
+ {
+ "name": "externalId",
+ "description": "External ID of the vulnerability identifier",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "externalType",
+ "description": "External type of the vulnerability identifier",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": "Name of the vulnerability identifier",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "url",
+ "description": "URL of the vulnerability identifier",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
"name": "VulnerabilityIssueLink",
"description": "Represents an issue link of a vulnerability.",
"fields": [
@@ -40958,6 +41081,47 @@
},
{
"kind": "OBJECT",
+ "name": "VulnerabilityScanner",
+ "description": "Represents a vulnerability scanner.",
+ "fields": [
+ {
+ "name": "externalId",
+ "description": "External ID of the vulnerability scanner",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": "Name of the vulnerability scanner",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
"name": "VulnerabilitySeveritiesCount",
"description": "Represents vulnerability counts by severity",
"fields": [
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 289a560f548..b60a1d1dfcf 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -926,7 +926,7 @@ Autogenerated return type of JiraImportUsers
| Name | Type | Description |
| --- | ---- | ---------- |
| `active` | Boolean | Indicates if the service is active |
-| `projects` | JiraProjectConnection | List of Jira projects fetched through Jira REST API |
+| `projects` | JiraProjectConnection | List of all Jira projects fetched through Jira REST API |
| `type` | String | Class name of the service |
## JiraUser
@@ -2014,9 +2014,12 @@ Represents a vulnerability.
| --- | ---- | ---------- |
| `description` | String | Description of the vulnerability |
| `id` | ID! | GraphQL ID of the vulnerability |
+| `identifiers` | VulnerabilityIdentifier! => 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 f640300e3ae..9d6bbf7f0e1 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 7ae3c9e9de2..4b3bf91030e 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 de43c504b05..6d44c56743e 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 4eaf3a0d4b4..7d15ae82b6f 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 9e1cdf0490c..c92ddf38ad2 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 119a53f5c35..e067ab6071e 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 85a33c608e5..192eeb691ff 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 f0b733d7e95..7d2a26b2d39 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 73b9800f0b8..7805b27902d 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 22abef98bf0..abb05ba56a7 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 b9e1e25a769..8e9ed753f09 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 02a67664a11..0cd75c89f42 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 bcd1a53bd47..72076fbecf9 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 00000000000..ca656705e07
--- /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 00000000000..b9f58587a58
--- /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 b78fc63b7dd..2322babcd53 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 cac16cf9cd8..e0830c290d1 100644
--- a/spec/fixtures/gitlab/import_export/corrupted_project_export.tar.gz
+++ b/spec/fixtures/gitlab/import_export/corrupted_project_export.tar.gz
Binary files 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 c01402954dd..0aa41734778 100644
--- a/spec/fixtures/gitlab/import_export/lightweight_project_export.tar.gz
+++ b/spec/fixtures/gitlab/import_export/lightweight_project_export.tar.gz
Binary files differ
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/project.json b/spec/fixtures/lib/gitlab/import_export/complex/project.json
index 0785da9c1bf..f6a6671b7f1 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 6d6afd3af0b..e5d39512255 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 326a2cef9ff..cef78316361 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 c5ae6bf4b04..414b68dacd7 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 cb07bcf8f28..92a136835bf 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 0877998cc9d..43230301296 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 364e2aa6ca8..156e10e4270 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 6fbbad017c5..15bb8ae5979 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 8c61e6c42a6..b664bb73176 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 588e5872cc8..0f7fa5f8e60 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 ab939e0d2f8..6818db48fee 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 e749ea6eacc..f2232ae8e9a 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 7f1c6224b7d..ba861aefe3c 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 20e85f0fd4b..5e2dd5f3fc9 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 6220d7b1fac..4024de38505 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 b8fff635e99..c82a3cc1bcf 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 ca6101364aa..8c914c6b74c 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 d67c89f18c9..4d44d55f2de 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 7ae382d8aae..966d6f7b106 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 9c3d17f7d8f..5424f67f445 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 00000000000..82c7ab7adaa
--- /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 f7b9aa7c00c..42d09da138b 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 198bedfe3bc..9072c41fe66 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 00000000000..ead18792efb
--- /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 f0722beb3ed..3125f8ba315 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 00000000000..c3e8f807afb
--- /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 cb36f74460d..00000000000
--- 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 6b482aa33a2..c5a68e51a1e 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"