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-11-19 06:08:59 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-11-19 06:08:59 +0300
commitb57142452211f98175ac75f473741c67988867f5 (patch)
tree504811360676d8b05aaa6249ad695488588be97d
parentb8e272100415ae1a550a455f4ad091fccb692a1e (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_manual_todo.yml1
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock6
-rw-r--r--app/graphql/mutations/issues/update.rb2
-rw-r--r--app/services/issuable/import_csv/base_service.rb8
-rw-r--r--changelogs/unreleased/246857-fix-issuable-import-csv-service.yml5
-rw-r--r--doc/api/features.md74
-rw-r--r--lib/api/entities/feature.rb10
-rw-r--r--lib/api/features.rb12
-rw-r--r--lib/feature.rb2
-rw-r--r--lib/feature/definition.rb14
-rw-r--r--spec/fixtures/csv_empty.csv0
-rw-r--r--spec/lib/banzai/filter/markdown_filter_spec.rb6
-rw-r--r--spec/requests/api/features_spec.rb166
-rw-r--r--spec/support/services/issuable_import_csv_service_shared_examples.rb32
15 files changed, 248 insertions, 92 deletions
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index b266435d4d2..b96cc49e01d 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -26,7 +26,6 @@ Graphql/IDType:
- 'ee/app/graphql/mutations/iterations/update.rb'
- 'ee/app/graphql/resolvers/iterations_resolver.rb'
- 'app/graphql/mutations/boards/issues/issue_move_list.rb'
- - 'app/graphql/mutations/issues/update.rb'
- 'app/graphql/mutations/metrics/dashboard/annotations/delete.rb'
- 'app/graphql/resolvers/design_management/design_at_version_resolver.rb'
- 'app/graphql/resolvers/design_management/design_resolver.rb'
diff --git a/Gemfile b/Gemfile
index d60fefe29dc..82a09e2f7eb 100644
--- a/Gemfile
+++ b/Gemfile
@@ -149,7 +149,7 @@ gem 'html-pipeline', '~> 2.12'
gem 'deckar01-task_list', '2.3.1'
gem 'gitlab-markup', '~> 1.7.1'
gem 'github-markup', '~> 1.7.0', require: 'github/markup'
-gem 'commonmarker', '~> 0.20'
+gem 'commonmarker', '~> 0.21'
gem 'kramdown', '~> 2.3.0'
gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~> 6.1.2'
diff --git a/Gemfile.lock b/Gemfile.lock
index 64179847dd8..807c24c0d31 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -177,7 +177,7 @@ GEM
open4 (~> 1.3)
coderay (1.1.3)
colored2 (3.1.2)
- commonmarker (0.20.1)
+ commonmarker (0.21.0)
ruby-enum (~> 0.5)
concord (0.1.5)
adamantium (~> 0.2.0)
@@ -1041,7 +1041,7 @@ GEM
rubocop-rspec (1.44.1)
rubocop (~> 0.87)
rubocop-ast (>= 0.7.1)
- ruby-enum (0.7.2)
+ ruby-enum (0.8.0)
i18n
ruby-fogbugz (0.2.1)
crack (~> 0.4)
@@ -1292,7 +1292,7 @@ DEPENDENCIES
capybara-screenshot (~> 1.0.22)
carrierwave (~> 1.3)
charlock_holmes (~> 0.7.7)
- commonmarker (~> 0.20)
+ commonmarker (~> 0.21)
concurrent-ruby (~> 1.1)
connection_pool (~> 2.0)
countries (~> 3.0)
diff --git a/app/graphql/mutations/issues/update.rb b/app/graphql/mutations/issues/update.rb
index 9b216b31f9b..d34e351b2a6 100644
--- a/app/graphql/mutations/issues/update.rb
+++ b/app/graphql/mutations/issues/update.rb
@@ -11,7 +11,7 @@ module Mutations
required: false,
description: copy_field_description(Types::IssueType, :title)
- argument :milestone_id, GraphQL::ID_TYPE,
+ argument :milestone_id, GraphQL::ID_TYPE, # rubocop: disable Graphql/IDType
required: false,
description: 'The ID of the milestone to assign to the issue. On update milestone will be removed if set to null'
diff --git a/app/services/issuable/import_csv/base_service.rb b/app/services/issuable/import_csv/base_service.rb
index bf5f643a51b..77a096e7586 100644
--- a/app/services/issuable/import_csv/base_service.rb
+++ b/app/services/issuable/import_csv/base_service.rb
@@ -38,7 +38,7 @@ module Issuable
def with_csv_lines
csv_data = @csv_io.open(&:read).force_encoding(Encoding::UTF_8)
- verify_headers!(csv_data)
+ validate_headers_presence!(csv_data.lines.first)
csv_parsing_params = {
col_sep: detect_col_sep(csv_data.lines.first),
@@ -49,9 +49,9 @@ module Issuable
CSV.new(csv_data, csv_parsing_params).each.with_index(2)
end
- def verify_headers!(data)
- headers = data.lines.first.downcase
- return if headers.include?('title') && headers.include?('description')
+ def validate_headers_presence!(headers)
+ headers.downcase! if headers
+ return if headers && headers.include?('title') && headers.include?('description')
raise CSV::MalformedCSVError
end
diff --git a/changelogs/unreleased/246857-fix-issuable-import-csv-service.yml b/changelogs/unreleased/246857-fix-issuable-import-csv-service.yml
new file mode 100644
index 00000000000..4e3bbfa49bc
--- /dev/null
+++ b/changelogs/unreleased/246857-fix-issuable-import-csv-service.yml
@@ -0,0 +1,5 @@
+---
+title: Fix error in Issuable::ImportCsv::BaseService when CSV file is empty
+merge_request: 47918
+author:
+type: fixed
diff --git a/doc/api/features.md b/doc/api/features.md
index bbf86eca490..f94f6b36ce2 100644
--- a/doc/api/features.md
+++ b/doc/api/features.md
@@ -37,7 +37,8 @@ Example response:
"key": "boolean",
"value": false
}
- ]
+ ],
+ "definition": null
},
{
"name": "my_user_feature",
@@ -47,7 +48,15 @@ Example response:
"key": "percentage_of_actors",
"value": 34
}
- ]
+ ],
+ "definition": {
+ "name": "my_user_feature",
+ "introduced_by_url": "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40880",
+ "rollout_issue_url": "https://gitlab.com/gitlab-org/gitlab/-/issues/244905",
+ "group": "group::ci",
+ "type": "development",
+ "default_enabled": false
+ }
},
{
"name": "new_library",
@@ -57,7 +66,45 @@ Example response:
"key": "boolean",
"value": true
}
- ]
+ ],
+ "definition": null
+ }
+]
+```
+
+## List all feature definitions
+
+Get a list of all feature definitions.
+
+```plaintext
+GET /features/definitions
+```
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/features/definitions"
+```
+
+Example response:
+
+```json
+[
+ {
+ "name": "api_kaminari_count_with_limit",
+ "introduced_by_url": "https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/23931",
+ "rollout_issue_url": null,
+ "milestone": "11.8",
+ "type": "ops",
+ "group": "group::ecosystem",
+ "default_enabled": false
+ },
+ {
+ "name": "marginalia",
+ "introduced_by_url": null,
+ "rollout_issue_url": null,
+ "milestone": null,
+ "type": "ops",
+ "group": null,
+ "default_enabled": false
}
]
```
@@ -81,6 +128,7 @@ POST /features/:name
| `user` | string | no | A GitLab username |
| `group` | string | no | A GitLab group's path, for example `gitlab-org` |
| `project` | string | no | A projects path, for example `gitlab-org/gitlab-foss` |
+| `force` | boolean | no | Skip feature flag validation checks, ie. YAML definition |
Note that you can enable or disable a feature for a `feature_group`, a `user`,
a `group`, and a `project` in a single API call.
@@ -104,7 +152,15 @@ Example response:
"key": "percentage_of_time",
"value": 30
}
- ]
+ ],
+ "definition": {
+ "name": "my_user_feature",
+ "introduced_by_url": "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40880",
+ "rollout_issue_url": "https://gitlab.com/gitlab-org/gitlab/-/issues/244905",
+ "group": "group::ci",
+ "type": "development",
+ "default_enabled": false
+ }
}
```
@@ -133,7 +189,15 @@ Example response:
"key": "percentage_of_actors",
"value": 42
}
- ]
+ ],
+ "definition": {
+ "name": "my_user_feature",
+ "introduced_by_url": "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40880",
+ "rollout_issue_url": "https://gitlab.com/gitlab-org/gitlab/-/issues/244905",
+ "group": "group::ci",
+ "type": "development",
+ "default_enabled": false
+ }
}
```
diff --git a/lib/api/entities/feature.rb b/lib/api/entities/feature.rb
index 618a7be9c7b..d1151849cd7 100644
--- a/lib/api/entities/feature.rb
+++ b/lib/api/entities/feature.rb
@@ -17,6 +17,16 @@ module API
{ key: gate.key, value: value }
end.compact
end
+
+ class Definition < Grape::Entity
+ ::Feature::Definition::PARAMS.each do |param|
+ expose param
+ end
+ end
+
+ expose :definition, using: Definition do |feature|
+ ::Feature::Definition.definitions[feature.name.to_sym]
+ end
end
end
end
diff --git a/lib/api/features.rb b/lib/api/features.rb
index 2c2e3e3d0c9..2ab60e2617d 100644
--- a/lib/api/features.rb
+++ b/lib/api/features.rb
@@ -46,6 +46,15 @@ module API
present features, with: Entities::Feature, current_user: current_user
end
+ desc 'Get a list of all feature definitions' do
+ success Entities::Feature::Definition
+ end
+ get :definitions do
+ definitions = ::Feature::Definition.definitions.values.map(&:to_h)
+
+ present definitions, with: Entities::Feature::Definition, current_user: current_user
+ end
+
desc 'Set the gate value for the given feature' do
success Entities::Feature
end
@@ -56,6 +65,7 @@ module API
optional :user, type: String, desc: 'A GitLab username'
optional :group, type: String, desc: "A GitLab group's path, such as 'gitlab-org'"
optional :project, type: String, desc: 'A projects path, like gitlab-org/gitlab-ce'
+ optional :force, type: Boolean, desc: 'Skip feature flag validation checks, ie. YAML definition'
mutually_exclusive :key, :feature_group
mutually_exclusive :key, :user
@@ -63,7 +73,7 @@ module API
mutually_exclusive :key, :project
end
post ':name' do
- validate_feature_flag_name!(params[:name])
+ validate_feature_flag_name!(params[:name]) unless params[:force]
feature = Feature.get(params[:name]) # rubocop:disable Gitlab/AvoidFeatureGet
targets = gate_targets(params)
diff --git a/lib/feature.rb b/lib/feature.rb
index 1f8c530bee5..c9871881dc9 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -136,8 +136,6 @@ class Feature
end
def register_definitions
- return unless check_feature_flags_definition?
-
Feature::Definition.reload!
end
diff --git a/lib/feature/definition.rb b/lib/feature/definition.rb
index 0ba1bdc4799..24f4cb3dbf0 100644
--- a/lib/feature/definition.rb
+++ b/lib/feature/definition.rb
@@ -13,6 +13,12 @@ class Feature
end
end
+ TYPES.each do |type, _|
+ define_method("#{type}?") do
+ attributes[:type].to_sym == type
+ end
+ end
+
def initialize(path, opts = {})
@path = path
@attributes = {}
@@ -94,6 +100,10 @@ class Feature
@definitions = load_all!
end
+ def has_definition?(key)
+ definitions.has_key?(key.to_sym)
+ end
+
def valid_usage!(key, type:, default_enabled:)
if definition = definitions[key.to_sym]
definition.valid_usage!(type_in_code: type, default_enabled_in_code: default_enabled)
@@ -119,10 +129,6 @@ class Feature
private
def load_all!
- # We currently do not load feature flag definitions
- # in production environments
- return [] unless Gitlab.dev_or_test_env?
-
paths.each_with_object({}) do |glob_path, definitions|
load_all_from_path!(definitions, glob_path)
end
diff --git a/spec/fixtures/csv_empty.csv b/spec/fixtures/csv_empty.csv
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/spec/fixtures/csv_empty.csv
diff --git a/spec/lib/banzai/filter/markdown_filter_spec.rb b/spec/lib/banzai/filter/markdown_filter_spec.rb
index 8d01a651651..c5e84a0c1e7 100644
--- a/spec/lib/banzai/filter/markdown_filter_spec.rb
+++ b/spec/lib/banzai/filter/markdown_filter_spec.rb
@@ -46,6 +46,12 @@ RSpec.describe Banzai::Filter::MarkdownFilter do
expect(result).to start_with('<pre><code lang="日">')
end
+
+ it 'works with additional language parameters' do
+ result = filter("```ruby:red gem\nsome code\n```", no_sourcepos: true)
+
+ expect(result).to start_with('<pre><code lang="ruby:red gem">')
+ end
end
end
diff --git a/spec/requests/api/features_spec.rb b/spec/requests/api/features_spec.rb
index 3f443b4f92b..acc49768545 100644
--- a/spec/requests/api/features_spec.rb
+++ b/spec/requests/api/features_spec.rb
@@ -6,6 +6,18 @@ RSpec.describe API::Features, stub_feature_flags: false do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
+ # Find any `development` feature flag name
+ let(:known_feature_flag) do
+ Feature::Definition.definitions
+ .values.find(&:development?)
+ end
+
+ let(:known_feature_flag_definition_hash) do
+ a_hash_including(
+ 'type' => 'development'
+ )
+ end
+
before do
Feature.reset
Flipper.unregister_groups
@@ -22,12 +34,14 @@ RSpec.describe API::Features, stub_feature_flags: false do
{
'name' => 'feature_1',
'state' => 'on',
- 'gates' => [{ 'key' => 'boolean', 'value' => true }]
+ 'gates' => [{ 'key' => 'boolean', 'value' => true }],
+ 'definition' => nil
},
{
'name' => 'feature_2',
'state' => 'off',
- 'gates' => [{ 'key' => 'boolean', 'value' => false }]
+ 'gates' => [{ 'key' => 'boolean', 'value' => false }],
+ 'definition' => nil
},
{
'name' => 'feature_3',
@@ -35,7 +49,14 @@ RSpec.describe API::Features, stub_feature_flags: false do
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'groups', 'value' => ['perf_team'] }
- ]
+ ],
+ 'definition' => nil
+ },
+ {
+ 'name' => known_feature_flag.name,
+ 'state' => 'on',
+ 'gates' => [{ 'key' => 'boolean', 'value' => true }],
+ 'definition' => known_feature_flag_definition_hash
}
]
end
@@ -44,6 +65,7 @@ RSpec.describe API::Features, stub_feature_flags: false do
Feature.enable('feature_1')
Feature.disable('feature_2')
Feature.enable('feature_3', Feature.group(:perf_team))
+ Feature.enable(known_feature_flag.name)
end
it 'returns a 401 for anonymous users' do
@@ -67,7 +89,7 @@ RSpec.describe API::Features, stub_feature_flags: false do
end
describe 'POST /feature' do
- let(:feature_name) { 'my_feature' }
+ let(:feature_name) { known_feature_flag.name }
context 'when the feature does not exist' do
it 'returns a 401 for anonymous users' do
@@ -87,43 +109,49 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: 'true' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'on',
- 'gates' => [{ 'key' => 'boolean', 'value' => true }])
+ 'gates' => [{ 'key' => 'boolean', 'value' => true }],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
it 'creates an enabled feature for the given Flipper group when passed feature_group=perf_team' do
post api("/features/#{feature_name}", admin), params: { value: 'true', feature_group: 'perf_team' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'groups', 'value' => ['perf_team'] }
- ])
+ ],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
it 'creates an enabled feature for the given user when passed user=username' do
post api("/features/#{feature_name}", admin), params: { value: 'true', user: user.username }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'actors', 'value' => ["User:#{user.id}"] }
- ])
+ ],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
it 'creates an enabled feature for the given user and feature group when passed user=username and feature_group=perf_team' do
post api("/features/#{feature_name}", admin), params: { value: 'true', user: user.username, feature_group: 'perf_team' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response['name']).to eq('my_feature')
+ expect(json_response['name']).to eq(feature_name)
expect(json_response['state']).to eq('conditional')
expect(json_response['gates']).to contain_exactly(
{ 'key' => 'boolean', 'value' => false },
@@ -141,13 +169,15 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: 'true', project: project.full_path }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'actors', 'value' => ["Project:#{project.id}"] }
- ])
+ ],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
end
@@ -156,12 +186,13 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: 'true', project: 'mep/to/the/mep/mep' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- "name" => "my_feature",
+ expect(json_response).to match(
+ "name" => feature_name,
"state" => "off",
"gates" => [
{ "key" => "boolean", "value" => false }
- ]
+ ],
+ 'definition' => known_feature_flag_definition_hash
)
end
end
@@ -175,13 +206,15 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: 'true', group: group.full_path }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'actors', 'value' => ["Group:#{group.id}"] }
- ])
+ ],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
end
@@ -190,12 +223,13 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: 'true', group: 'not/a/group' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- "name" => "my_feature",
+ expect(json_response).to match(
+ "name" => feature_name,
"state" => "off",
"gates" => [
{ "key" => "boolean", "value" => false }
- ]
+ ],
+ 'definition' => known_feature_flag_definition_hash
)
end
end
@@ -205,26 +239,30 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: '50' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'percentage_of_time', 'value' => 50 }
- ])
+ ],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
it 'creates a feature with the given percentage of actors if passed an integer' do
post api("/features/#{feature_name}", admin), params: { value: '50', key: 'percentage_of_actors' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'percentage_of_actors', 'value' => 50 }
- ])
+ ],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
end
@@ -238,36 +276,42 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: 'true' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'on',
- 'gates' => [{ 'key' => 'boolean', 'value' => true }])
+ 'gates' => [{ 'key' => 'boolean', 'value' => true }],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
it 'enables the feature for the given Flipper group when passed feature_group=perf_team' do
post api("/features/#{feature_name}", admin), params: { value: 'true', feature_group: 'perf_team' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'groups', 'value' => ['perf_team'] }
- ])
+ ],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
it 'enables the feature for the given user when passed user=username' do
post api("/features/#{feature_name}", admin), params: { value: 'true', user: user.username }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'actors', 'value' => ["User:#{user.id}"] }
- ])
+ ],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
end
@@ -279,10 +323,12 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: 'false' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'off',
- 'gates' => [{ 'key' => 'boolean', 'value' => false }])
+ 'gates' => [{ 'key' => 'boolean', 'value' => false }],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
it 'disables the feature for the given Flipper group when passed feature_group=perf_team' do
@@ -292,10 +338,12 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: 'false', feature_group: 'perf_team' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'off',
- 'gates' => [{ 'key' => 'boolean', 'value' => false }])
+ 'gates' => [{ 'key' => 'boolean', 'value' => false }],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
it 'disables the feature for the given user when passed user=username' do
@@ -305,10 +353,12 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: 'false', user: user.username }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'off',
- 'gates' => [{ 'key' => 'boolean', 'value' => false }])
+ 'gates' => [{ 'key' => 'boolean', 'value' => false }],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
end
@@ -321,13 +371,15 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: '30' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'percentage_of_time', 'value' => 30 }
- ])
+ ],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
end
@@ -340,13 +392,15 @@ RSpec.describe API::Features, stub_feature_flags: false do
post api("/features/#{feature_name}", admin), params: { value: '74', key: 'percentage_of_actors' }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response).to eq(
- 'name' => 'my_feature',
+ expect(json_response).to match(
+ 'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'percentage_of_actors', 'value' => 74 }
- ])
+ ],
+ 'definition' => known_feature_flag_definition_hash
+ )
end
end
end
diff --git a/spec/support/services/issuable_import_csv_service_shared_examples.rb b/spec/support/services/issuable_import_csv_service_shared_examples.rb
index 20ac2ff5c7c..f68750bec32 100644
--- a/spec/support/services/issuable_import_csv_service_shared_examples.rb
+++ b/spec/support/services/issuable_import_csv_service_shared_examples.rb
@@ -26,29 +26,33 @@ RSpec.shared_examples 'issuable import csv service' do |issuable_type|
end
end
+ shared_examples_for 'invalid file' do
+ it 'returns invalid file error' do
+ expect(subject[:success]).to eq(0)
+ expect(subject[:parse_error]).to eq(true)
+ end
+
+ it_behaves_like 'importer with email notification'
+ it_behaves_like 'an issuable importer'
+ end
+
describe '#execute' do
- context 'invalid file' do
+ context 'invalid file extension' do
let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') }
- it 'returns invalid file error' do
- expect(subject[:success]).to eq(0)
- expect(subject[:parse_error]).to eq(true)
- end
+ it_behaves_like 'invalid file'
+ end
- it_behaves_like 'importer with email notification'
- it_behaves_like 'an issuable importer'
+ context 'empty file' do
+ let(:file) { fixture_file_upload('spec/fixtures/csv_empty.csv') }
+
+ it_behaves_like 'invalid file'
end
context 'file without headers' do
let(:file) { fixture_file_upload('spec/fixtures/csv_no_headers.csv') }
- it 'returns invalid file error' do
- expect(subject[:success]).to eq(0)
- expect(subject[:parse_error]).to eq(true)
- end
-
- it_behaves_like 'importer with email notification'
- it_behaves_like 'an issuable importer'
+ it_behaves_like 'invalid file'
end
context 'with a file generated by Gitlab CSV export' do