Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-08-03 12:09:47 +00:00
parent cb48c93abf
commit a70e2c0418
16 changed files with 474 additions and 55 deletions

View File

@ -336,6 +336,15 @@ Graphql/AuthorizeTypes:
- 'spec/**/*.rb'
- 'ee/spec/**/*.rb'
Graphql/JSONType:
Enabled: true
Include:
- 'app/graphql/types/**/*'
- 'ee/app/graphql/types/**/*'
Exclude:
- 'spec/**/*.rb'
- 'ee/spec/**/*.rb'
RSpec/EnvAssignment:
Enable: true
Include:

View File

@ -1249,24 +1249,6 @@ Rails/SaveBang:
Exclude:
- 'ee/spec/controllers/projects/merge_requests_controller_spec.rb'
- 'ee/spec/controllers/subscriptions_controller_spec.rb'
- 'ee/spec/features/admin/admin_users_spec.rb'
- 'ee/spec/features/admin/geo/admin_geo_nodes_spec.rb'
- 'ee/spec/features/admin/licenses/admin_views_license_spec.rb'
- 'ee/spec/features/boards/scoped_issue_board_spec.rb'
- 'ee/spec/features/ci_shared_runner_warnings_spec.rb'
- 'ee/spec/features/dashboards/operations_spec.rb'
- 'ee/spec/features/issues/gfm_autocomplete_ee_spec.rb'
- 'ee/spec/features/merge_request/user_approves_spec.rb'
- 'ee/spec/features/merge_requests/user_views_all_merge_requests_spec.rb'
- 'ee/spec/features/projects/members/invite_group_and_members_spec.rb'
- 'ee/spec/features/projects/merge_requests/user_approves_merge_request_spec.rb'
- 'ee/spec/features/projects/mirror_spec.rb'
- 'ee/spec/features/projects/new_project_spec.rb'
- 'ee/spec/features/projects/settings/user_manages_approval_settings_spec.rb'
- 'ee/spec/features/projects/settings/user_manages_members_spec.rb'
- 'ee/spec/features/search/elastic/global_search_spec.rb'
- 'ee/spec/features/security/project/internal_access_spec.rb'
- 'ee/spec/features/security/project/public_access_spec.rb'
- 'ee/spec/finders/epics_finder_spec.rb'
- 'ee/spec/finders/security/vulnerabilities_finder_spec.rb'
- 'ee/spec/frontend/fixtures/analytics.rb'

View File

@ -71,7 +71,7 @@ module Types
description: 'Number of events of this alert',
method: :events
field :details,
field :details, # rubocop:disable Graphql/JSONType
GraphQL::Types::JSON,
null: true,
description: 'Alert details'

View File

@ -56,7 +56,7 @@ class Service < ApplicationRecord
validates :instance, uniqueness: { scope: :type }, if: -> { instance? }
validate :validate_is_instance_or_template
scope :issue_trackers, -> { where(category: 'issue_tracker') }
scope :external_issue_trackers, -> { where(category: 'issue_tracker').active }
scope :external_wikis, -> { where(type: 'ExternalWikiService').active }
scope :active, -> { where(active: true) }
scope :by_type, -> (type) { where(type: type) }
@ -76,7 +76,6 @@ class Service < ApplicationRecord
scope :wiki_page_hooks, -> { where(wiki_page_events: true, active: true) }
scope :deployment_hooks, -> { where(deployment_events: true, active: true) }
scope :alert_hooks, -> { where(alert_events: true, active: true) }
scope :external_issue_trackers, -> { issue_trackers.active }
scope :deployment, -> { where(category: 'deployment') }
default_value_for :category, 'common'

View File

@ -0,0 +1,5 @@
---
title: Refactor ee/spec/features/* to fix SaveBang Cop
merge_request: 38289
author: Rajendra Kadam
type: fixed

View File

@ -325,9 +325,11 @@ Example response:
"design_repositories_failed_count": nil,
"design_repositories_synced_in_percentage": "0.00%",
"projects_count": 41,
"repositories_count": 41,
"repositories_failed_count": nil,
"repositories_synced_count": nil,
"repositories_synced_in_percentage": "0.00%",
"wikis_count": 41,
"wikis_failed_count": nil,
"wikis_synced_count": nil,
"wikis_synced_in_percentage": "0.00%",
@ -402,9 +404,11 @@ Example response:
"design_repositories_failed_count": nil,
"design_repositories_synced_in_percentage": "0.00%",
"projects_count": 41,
"repositories_count": 41,
"repositories_failed_count": 1,
"repositories_synced_count": 40,
"repositories_synced_in_percentage": "97.56%",
"wikis_count": 41,
"wikis_failed_count": 0,
"wikis_synced_count": 41,
"wikis_synced_in_percentage": "100.00%",
@ -448,9 +452,6 @@ Example response:
]
```
NOTE: **Note:**
In GitLab 12.0, deprecated fields `wikis_count` and `repositories_count` were removed. Use `projects_count` instead.
## Retrieve status about a specific Geo node
```plaintext
@ -495,9 +496,11 @@ Example response:
"design_repositories_failed_count": nil,
"design_repositories_synced_in_percentage": "0.00%",
"projects_count": 41,
"repositories_count": 41,
"repositories_failed_count": 1,
"repositories_synced_count": 40,
"repositories_synced_in_percentage": "97.56%",
"wikis_count": 41,
"wikis_failed_count": 0,
"wikis_synced_count": 41,
"wikis_synced_in_percentage": "100.00%",
@ -517,9 +520,6 @@ Example response:
Note: The `health_status` parameter can only be in an "Healthy" or "Unhealthy" state, while the `health` parameter can be empty, "Healthy", or contain the actual error message.
NOTE: **Note:**
In GitLab 12.0, deprecated fields `wikis_count` and `repositories_count` were removed. Use `projects_count` instead.
## Retrieve project sync or verification failures that occurred on the current node
This only works on a secondary node.

View File

@ -1964,7 +1964,12 @@ input CreateIterationInput {
"""
The target group for the iteration
"""
groupPath: ID!
groupPath: ID
"""
The target project for the iteration
"""
projectPath: ID
"""
The start date of the iteration
@ -9714,6 +9719,68 @@ type Project {
"""
issuesEnabled: Boolean
"""
Find iterations
"""
iterations(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
List items within a time frame where items.end_date is between startDate and
endDate parameters (startDate parameter must be present)
"""
endDate: Time
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
The ID of the Iteration to look up
"""
id: ID
"""
The internal ID of the Iteration to look up
"""
iid: ID
"""
Whether to include ancestor iterations. Defaults to true
"""
includeAncestors: Boolean
"""
Returns the last _n_ elements from the list.
"""
last: Int
"""
List items within a time frame where items.start_date is between startDate
and endDate parameters (endDate parameter must be present)
"""
startDate: Time
"""
Filter iterations by state
"""
state: IterationState
"""
Fuzzy search by title
"""
title: String
): IterationConnection
"""
Status of Jira import background job of the project
"""

View File

@ -5202,13 +5202,19 @@
"name": "groupPath",
"description": "The target group for the iteration",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
"kind": "SCALAR",
"name": "ID",
"ofType": null
},
"defaultValue": null
},
{
"name": "projectPath",
"description": "The target project for the iteration",
"type": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
},
"defaultValue": null
},
@ -28960,6 +28966,129 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "iterations",
"description": "Find iterations",
"args": [
{
"name": "startDate",
"description": "List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)",
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"defaultValue": null
},
{
"name": "endDate",
"description": "List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)",
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"defaultValue": null
},
{
"name": "state",
"description": "Filter iterations by state",
"type": {
"kind": "ENUM",
"name": "IterationState",
"ofType": null
},
"defaultValue": null
},
{
"name": "title",
"description": "Fuzzy search by title",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "id",
"description": "The ID of the Iteration to look up",
"type": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
},
"defaultValue": null
},
{
"name": "iid",
"description": "The internal ID of the Iteration to look up",
"type": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
},
"defaultValue": null
},
{
"name": "includeAncestors",
"description": "Whether to include ancestor iterations. Defaults to true",
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"defaultValue": null
},
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "before",
"description": "Returns the elements in the list that come before the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "first",
"description": "Returns the first _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
},
{
"name": "last",
"description": "Returns the last _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "IterationConnection",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "jiraImportStatus",
"description": "Status of Jira import background job of the project",

View File

@ -9,6 +9,11 @@ You can only restore a backup to **exactly the same version and type (CE/EE)**
of GitLab on which it was created. The best way to migrate your repositories
from one server to another is through backup restore.
CAUTION: **Warning:**
GitLab will not backup items that are not stored on the
filesystem. If using [object storage](../administration/object_storage.md),
remember to enable backups with your object storage provider if desired.
## Requirements
In order to be able to backup and restore, you need two essential tools

View File

@ -271,6 +271,7 @@ The following issue metadata will be copied to the epic:
- Upvotes/downvotes.
- Participants.
- Group labels that the issue already has.
- Parent epic. **(ULTIMATE)**
## Manage multi-level child epics **(ULTIMATE)**

View File

@ -10,6 +10,23 @@ module API
requires :ref, type: String, desc: 'The name of branch, tag or commit'
end
params :create_file_params do
optional :files, type: Array, desc: 'An array of files' do
requires :file_path, type: String, file_path: true, allow_blank: false, desc: 'The path of a snippet file'
requires :content, type: String, allow_blank: false, desc: 'The content of a snippet file'
end
optional :content, type: String, allow_blank: false, desc: 'The content of a snippet'
given :content do
requires :file_name, type: String, desc: 'The name of a snippet file'
end
mutually_exclusive :files, :content
exactly_one_of :files, :content
end
def content_for(snippet)
if snippet.empty_repo?
env['api.format'] = :txt
@ -35,5 +52,12 @@ module API
send_git_blob(repo, blob)
end
end
def process_file_args(args)
args[:snippet_actions] = args.delete(:files)&.map do |file|
file[:action] = :create
file.symbolize_keys
end
end
end
end

View File

@ -66,18 +66,23 @@ module API
end
params do
requires :title, type: String, allow_blank: false, desc: 'The title of a snippet'
requires :file_name, type: String, desc: 'The name of a snippet file'
requires :content, type: String, allow_blank: false, desc: 'The content of a snippet'
optional :description, type: String, desc: 'The description of a snippet'
optional :visibility, type: String,
values: Gitlab::VisibilityLevel.string_values,
default: 'internal',
desc: 'The visibility of the snippet'
use :create_file_params
end
post do
authorize! :create_snippet
attrs = declared_params(include_missing: false).merge(request: request, api: true)
attrs = declared_params(include_missing: false).tap do |create_args|
create_args[:request] = request
create_args[:api] = true
process_file_args(create_args)
end
service_response = ::Snippets::CreateService.new(nil, current_user, attrs).execute
snippet = service_response.payload[:snippet]

View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
# This cop checks for use of GraphQL::Types::JSON types in GraphQL fields
# and arguments.
#
# @example
#
# # bad
# class AwfulClass
# field :some_field, GraphQL::Types::JSON
# end
#
# # good
# class GreatClass
# field :some_field, GraphQL::STRING_TYPE
# end
module RuboCop
module Cop
module Graphql
class JSONType < RuboCop::Cop::Cop
MSG = 'Avoid using GraphQL::Types::JSON. See: ' \
'https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#json'.freeze
def_node_matcher :has_json_type?, <<~PATTERN
(send nil? {:field :argument}
(sym _)
(const
(const
(const nil? :GraphQL) :Types) :JSON)
(...)?)
PATTERN
def on_send(node)
add_offense(node, location: :expression) if has_json_type?(node)
end
end
end
end
end

View File

@ -217,7 +217,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures do
it_behaves_like 'all pipelines'
it 'includes custom filters', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/233077' do
it 'includes custom filters' do
aggregate_failures 'UploadLinkFilter' do
expect(doc).to parse_upload_links
end
@ -282,7 +282,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures do
it_behaves_like 'all pipelines'
it 'includes custom filters', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/233077' do
it 'includes custom filters' do
aggregate_failures 'UploadLinkFilter' do
expect(doc).to parse_upload_links
end

View File

@ -229,13 +229,15 @@ RSpec.describe API::Snippets do
let(:base_params) do
{
title: 'Test Title',
file_name: 'test.rb',
description: 'test description',
content: 'puts "hello world"',
visibility: 'public'
}
end
let(:params) { base_params.merge(extra_params) }
let(:file_path) { 'file_1.rb' }
let(:file_content) { 'puts "hello world"' }
let(:params) { base_params.merge(file_params, extra_params) }
let(:file_params) { { files: [{ file_path: file_path, content: file_content }] } }
let(:extra_params) { {} }
subject { post api("/snippets/", user), params: params }
@ -251,7 +253,7 @@ RSpec.describe API::Snippets do
expect(response).to have_gitlab_http_status(:created)
expect(json_response['title']).to eq(params[:title])
expect(json_response['description']).to eq(params[:description])
expect(json_response['file_name']).to eq(params[:file_name])
expect(json_response['file_name']).to eq(file_path)
expect(json_response['files']).to eq(snippet.blobs.map { |blob| snippet_blob_file(blob) })
expect(json_response['visibility']).to eq(params[:visibility])
end
@ -265,9 +267,90 @@ RSpec.describe API::Snippets do
it 'commit the files to the repository' do
subject
blob = snippet.repository.blob_at('master', params[:file_name])
blob = snippet.repository.blob_at('master', file_path)
expect(blob.data).to eq params[:content]
expect(blob.data).to eq file_content
end
end
context 'with files parameter' do
using RSpec::Parameterized::TableSyntax
where(:path, :content, :status, :error) do
'.gitattributes' | 'file content' | :created | nil
'valid/path/file.rb' | 'file content' | :created | nil
'.gitattributes' | nil | :bad_request | 'files[0][content] is empty'
'.gitattributes' | '' | :bad_request | 'files[0][content] is empty'
'' | 'file content' | :bad_request | 'files[0][file_path] is empty'
nil | 'file content' | :bad_request | 'files[0][file_path] should be a valid file path, files[0][file_path] is empty'
'../../etc/passwd' | 'file content' | :bad_request | 'files[0][file_path] should be a valid file path'
end
with_them do
let(:file_path) { path }
let(:file_content) { content }
before do
subject
end
it 'responds correctly' do
expect(response).to have_gitlab_http_status(status)
expect(json_response['error']).to eq(error)
end
end
it 'returns 400 if both files and content are provided' do
params[:file_name] = 'foo.rb'
params[:content] = 'bar'
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq 'files, content are mutually exclusive'
end
it 'returns 400 when neither files or content are provided' do
params.delete(:files)
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq 'files, content are missing, exactly one parameter must be provided'
end
context 'with multiple files' do
let(:file_params) do
{
files: [
{ file_path: 'file_1.rb', content: 'puts "hello world"' },
{ file_path: 'file_2.rb', content: 'puts "hello world 2"' }
]
}
end
it_behaves_like 'snippet creation'
end
end
context 'without files parameter' do
let(:file_params) { { file_name: 'testing.rb', content: 'snippet content' } }
it 'allows file_name and content parameters' do
subject
expect(response).to have_gitlab_http_status(:created)
end
it 'returns 400 if file_name and content are not both provided' do
params.delete(:file_name)
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq 'file_name is missing'
end
end
@ -305,15 +388,6 @@ RSpec.describe API::Snippets do
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'returns 400 if content is blank' do
params[:content] = ''
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq 'content is empty'
end
it 'returns 400 if title is blank' do
params[:title] = ''

View File

@ -0,0 +1,79 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop'
require_relative '../../../../rubocop/cop/graphql/json_type'
RSpec.describe RuboCop::Cop::Graphql::JSONType, type: :rubocop do
include CopHelper
subject(:cop) { described_class.new }
context 'fields' do
it 'adds an offense when GraphQL::Types::JSON is used' do
inspect_source(<<~RUBY.strip)
class MyType
field :some_field, GraphQL::Types::JSON
end
RUBY
expect(cop.offenses.size).to eq(1)
end
it 'adds an offense when GraphQL::Types::JSON is used with other keywords' do
inspect_source(<<~RUBY.strip)
class MyType
field :some_field, GraphQL::Types::JSON, null: true, description: 'My description'
end
RUBY
expect(cop.offenses.size).to eq(1)
end
it 'does not add an offense for other types' do
expect_no_offenses(<<~RUBY.strip)
class MyType
field :some_field, GraphQL::STRING_TYPE
end
RUBY
end
end
context 'arguments' do
it 'adds an offense when GraphQL::Types::JSON is used' do
inspect_source(<<~RUBY.strip)
class MyType
argument :some_arg, GraphQL::Types::JSON
end
RUBY
expect(cop.offenses.size).to eq(1)
end
it 'adds an offense when GraphQL::Types::JSON is used with other keywords' do
inspect_source(<<~RUBY.strip)
class MyType
argument :some_arg, GraphQL::Types::JSON, null: true, description: 'My description'
end
RUBY
expect(cop.offenses.size).to eq(1)
end
it 'does not add an offense for other types' do
expect_no_offenses(<<~RUBY.strip)
class MyType
argument :some_arg, GraphQL::STRING_TYPE
end
RUBY
end
end
it 'does not add an offense for uses outside of field or argument' do
expect_no_offenses(<<~RUBY.strip)
class MyType
foo :some_field, GraphQL::Types::JSON
end
RUBY
end
end