Commit 1ad243d2 authored by Alex Kalderimis's avatar Alex Kalderimis

Merge branch 'remove-json-schemer-gem' into 'master'

Stop using json shema gem in test [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!58661
parents 5dbbabc4 53cdadc0
......@@ -417,7 +417,6 @@ group :development, :test, :omnibus do
end
group :test do
gem 'json-schema', '~> 2.8.0'
gem 'fuubar', '~> 2.2.0'
gem 'rspec-retry', '~> 0.6.1'
gem 'rspec_profiling', '~> 0.0.6'
......
......@@ -652,8 +652,6 @@ GEM
activesupport (>= 4.2)
aes_key_wrap
bindata
json-schema (2.8.1)
addressable (>= 2.4)
json_schemer (0.2.12)
ecma-re-validator (~> 0.2)
hana (~> 1.3)
......@@ -1491,7 +1489,6 @@ DEPENDENCIES
jira-ruby (~> 2.1.4)
js_regex (~> 3.4)
json (~> 2.3.0)
json-schema (~> 2.8.0)
json_schemer (~> 0.2.12)
jwt (~> 2.1.0)
kaminari (~> 1.0)
......
......@@ -25,7 +25,7 @@
]
},
"logs_path": { "type": "string" },
"updated_at": { "type": "date" }
"updated_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"projects"
......
......@@ -9,14 +9,14 @@
"description": { "type": ["string" , "null"] },
"confidential": { "type": "boolean" },
"state": { "type": "string" },
"start_date": { "type": ["date", "null"] },
"start_date_fixed": { "type": ["date", "null"] },
"start_date": { "type": ["string", "null"], "format": "date-time"},
"start_date_fixed": { "type": ["string", "null"], "format": "date-time" },
"start_date_is_fixed": { "type": "boolean" },
"start_date_from_milestones": { "type": ["date", "null"] },
"end_date": { "type": ["date", "null"] },
"due_date": { "type": ["date", "null"] },
"due_date_fixed": { "type": ["date", "null"] },
"due_date_from_milestones": { "type": ["date", "null"] },
"start_date_from_milestones": { "type": ["string", "null"], "format": "date-time" },
"end_date": { "type": ["string", "null"], "format": "date-time" },
"due_date": { "type": ["string", "null"], "format": "date-time" },
"due_date_fixed": { "type": ["string", "null"], "format": "date-time" },
"due_date_from_milestones": { "type": ["string", "null"], "format": "date-time" },
"due_date_is_fixed": { "type": "boolean" },
"web_url": { "type": "string" },
"labels": { "type": ["array", "null"] },
......
{
"type": "object",
"properties" : {
"author_email_regex": { "type": ["string", null] },
"branch_name_regex": { "type": ["string", null] },
"author_email_regex": { "type": ["string", "null"] },
"branch_name_regex": { "type": ["string", "null"] },
"commit_committer_check": { "type": "boolean" },
"commit_message_negative_regex": { "type": ["string", null] },
"commit_message_regex": { "type": ["string", null] },
"created_at": { "type": "date" },
"deny_delete_tag": { "type": ["boolean", null] },
"file_name_regex": { "type": ["string", null] },
"commit_message_negative_regex": { "type": ["string", "null"] },
"commit_message_regex": { "type": ["string", "null"] },
"created_at": { "type": "string", "format": "date-time" },
"deny_delete_tag": { "type": ["boolean", "null"] },
"file_name_regex": { "type": ["string", "null"] },
"id": { "type": "integer" },
"max_file_size": { "type": "integer" },
"member_check": { "type": "boolean" },
......
......@@ -10,8 +10,8 @@
"state": { "type": "string" },
"created_at": { "type": "string" },
"updated_at": { "type": "string" },
"start_date": { "type": ["date", "null"] },
"due_date": { "type": ["date", "null"] },
"start_date": { "type": ["string", "null"], "format": "date-time" },
"due_date": { "type": ["string", "null"], "format": "date-time" },
"expired": { "type": ["boolean", "null"] },
"web_url": { "type": "string" }
},
......
......@@ -67,12 +67,8 @@
"enable_advanced_logs_querying": {
"type": "boolean"
},
"created_at": {
"type": "date"
},
"updated_at": {
"type": "date"
},
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"can_stop": {
"type": "boolean"
},
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"type": "object",
"required": ["epic_id", "created", "author", "ancestors", "todo_exists", "todo_path", "lock_version",
......@@ -79,7 +80,7 @@
"lock_version": {
"type": [
"integer",
null
"null"
]
},
"state": {
......@@ -109,7 +110,7 @@
"start_date": {
"type": [
"string",
null
"null"
]
},
"start_date_is_fixed": {
......@@ -118,13 +119,13 @@
"start_date_fixed": {
"type": [
"string",
null
"null"
]
},
"start_date_from_milestones": {
"type": [
"string",
null
"null"
]
},
"start_date_sourcing_milestone_title": {
......@@ -143,13 +144,13 @@
"start_date": {
"type": [
"string",
null
"null"
]
},
"due_date": {
"type": [
"string",
null
"null"
]
}
}
......@@ -157,7 +158,7 @@
"due_date": {
"type": [
"string",
null
"null"
]
},
"due_date_is_fixed": {
......@@ -166,13 +167,13 @@
"due_date_fixed": {
"type": [
"string",
null
"null"
]
},
"due_date_from_milestones": {
"type": [
"string",
null
"null"
]
},
"due_date_sourcing_milestone_title": {
......@@ -191,13 +192,13 @@
"start_date": {
"type": [
"string",
null
"null"
]
},
"due_date": {
"type": [
"string",
null
"null"
]
}
}
......
......@@ -42,7 +42,18 @@
],
"properties": {
"id": { "type": "integer" },
"title": { "type": "string" }
"title": { "type": "string" },
"state": { "type": "string" },
"created_at": { "type": ["string", "null"] },
"updated_at": { "type": ["string", "null"] },
"due_date": { "type": ["string", "null"] },
"start_date": { "type": ["string", "null"] },
"expired": { "type": ["string", "null"] },
"web_url": { "type": "string" },
"description": { "type": [ "string", "null"] },
"iid": { "type": "integer" },
"group_id": { "type": "integer" },
"project_id": { "type": "integer" }
},
"additionalProperties": false
},
......
......@@ -28,16 +28,16 @@
},
"upvotes": { "type": "integer" },
"downvotes": { "type": "integer" },
"start_date": { "type": ["date", "null"] },
"start_date_fixed": { "type": ["date", "null"] },
"start_date_from_milestones": { "type": ["date", "null"] },
"start_date_from_inherited_source": { "type": ["date", "null"] },
"start_date": { "type": ["string", "null"], "format": "date" },
"start_date_fixed": { "type": ["string", "null"], "format": "date" },
"start_date_from_milestones": { "type": ["string", "null"], "format": "date-time" },
"start_date_from_inherited_source": { "type": ["string", "null"], "format": "date-time" },
"start_date_is_fixed": { "type": "boolean" },
"end_date": { "type": ["date", "null"] },
"due_date": { "type": ["date", "null"] },
"due_date_fixed": { "type": ["date", "null"] },
"due_date_from_milestones": { "type": ["date", "null"] },
"due_date_from_inherited_source": { "type": ["date", "null"] },
"end_date": { "type": ["string", "null"], "format": "date" },
"due_date": { "type": ["string", "null"], "format": "date" },
"due_date_fixed": { "type": ["string", "null"], "format": "date" },
"due_date_from_milestones": { "type": ["string", "null"], "format": "date-time" },
"due_date_from_inherited_source": { "type": ["string", "null"], "format": "date-time" },
"due_date_is_fixed": { "type": "boolean" },
"state": { "type": "string" },
"created_at": { "type": ["string", "null"] },
......
......@@ -25,7 +25,7 @@
"id": { "type": "integer" },
"group_id": { "type": "integer" },
"url": { "type": "string" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"push_events": { "type": "boolean" },
"tag_push_events": { "type": "boolean" },
"merge_requests_events": { "type": "boolean" },
......
......@@ -10,7 +10,7 @@
],
"properties" : {
"id": { "type": "integer" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"state": { "type": "string" },
"source_storage_name": { "type": "string" },
"destination_storage_name": { "type": "string" },
......
......@@ -10,7 +10,7 @@
"avatar_url": { "type": ["string", "null"] },
"web_url": { "type": ["string", "null"] },
"access_level": { "type": "integer" },
"expires_at": { "type": ["date", "null"] },
"expires_at": { "type": ["string", "null"], "format": "date-time" },
"is_using_seat": { "type": "boolean" },
"is_gitlab_employee": { "type": "boolean" }
},
......
......@@ -12,11 +12,11 @@
"pipeline": {
"$ref": "../../../../../../../spec/fixtures/api/schemas/public_api/v4/pipeline.json"
},
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"target_branch": { "type": "string" },
"status": { "type": "string" },
"merged_at": { "type": ["date", "null"] },
"merged_at": { "type": ["string", "null"], "format": "date-time" },
"duration": { "type": ["integer", "null"] }
},
"additionalProperties": false
......
......@@ -36,14 +36,14 @@
"dismissed_by_id": { "type": ["integer", "null"] },
"confirmed_by_id": { "type": ["integer", "null"] },
"closed_by_id": { "type": ["integer", "null"] },
"start_date": { "type": ["date", "null"] },
"due_date": { "type": ["date", "null"] },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"last_edited_at": { "type": "date" },
"resolved_at": { "type": "date" },
"dismissed_at": { "type": "date" },
"confirmed_at": { "type": "date" },
"closed_at": { "type": "date" }
"start_date": { "type": ["string", "null"], "format": "date-time" },
"due_date": { "type": ["string", "null"], "format": "date-time" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"last_edited_at": { "type": ["string", "null"], "format": "date-time" },
"resolved_at": { "type": ["string", "null"], "format": "date-time" },
"dismissed_at": { "type": ["string", "null"], "format": "date-time" },
"confirmed_at": { "type": ["string", "null"], "format": "date-time" },
"closed_at": { "type": "string", "format": "date-time" }
}
}
......@@ -13,7 +13,7 @@
],
"properties" : {
"id": { "type": "integer" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"project_id": { "type": ["integer", "null"] },
"group_id": { "type": ["integer", "null"] },
"format": {
......@@ -24,8 +24,8 @@
"type": "string",
"enum": ["created", "running", "finished", "failed"]
},
"started_at": { "type": ["date", "null"] },
"finished_at": { "type": ["date", "null"] },
"started_at": { "type": ["string", "null"] },
"finished_at": { "type": ["string", "null"] },
"_links": {
"type": "object",
"required": ["self", "download"],
......
......@@ -16,7 +16,7 @@
},
"additionalProperties": false
},
"updated_at": { "type": "date" },
"created_at": { "type": "date" }
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" }
}
}
......@@ -10,7 +10,7 @@
"required": ["note", "created_at"],
"properties": {
"note": { "type": "string" },
"created_at": { "type": "date" }
"created_at": { "type": "string", "format": "date-time"}
},
"additionalProperties": false
}
......
......@@ -10,7 +10,7 @@
],
"properties" : {
"id": { "type": "integer" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time"},
"project_id": { "type": "integer" },
"author": { "$ref": "../../../../../spec/fixtures/api/schemas/entities/user.json" },
"comment_details": {
......@@ -37,7 +37,7 @@
"project_fingerprint": { "type": "string" },
"branch": { "type": ["string", "null"] },
"destroy_vulnerability_feedback_dismissal_path": { "type": "string" },
"finding_uuid": { "type": ["string", "null"] },
"finding_uuid": { "type": ["string", "null"] },
"dismissal_reason": { "type": ["string", "null"] },
"dismissal_descriptions": {
"type": {"string": "string"}
......
......@@ -17,8 +17,8 @@
"anomalous": { "type": ["array"] }
},
"interval": { "type": "string" },
"from": { "type": "date" },
"to": { "type": "date" },
"from": { "type": "string", "format": "date-time" },
"to": { "type": "string", "format": "date-time" },
"status": { "type": "string", "enum": ["success", "failure"] }
},
"additionalProperties": false
......
......@@ -30,7 +30,7 @@ RSpec.describe Clusters::EnvironmentEntity do
end
it 'matches expected schema' do
expect(subject.with_indifferent_access).to match_schema('clusters/environment', dir: 'ee')
expect(subject.to_json).to match_schema('clusters/environment', dir: 'ee')
end
it 'exposes rollout_status' do
......@@ -44,7 +44,7 @@ RSpec.describe Clusters::EnvironmentEntity do
end
it 'matches expected schema' do
expect(subject.with_indifferent_access).to match_schema('clusters/environment', dir: 'ee')
expect(subject.to_json).to match_schema('clusters/environment', dir: 'ee')
end
it 'does not expose rollout_status' do
......
......@@ -18,6 +18,6 @@ RSpec.describe Clusters::EnvironmentSerializer do
end
it 'matches clusters/environment json schema' do
expect(json_entity).to match_schema('clusters/environment', dir: 'ee')
expect(json_entity.to_json).to match_schema('clusters/environment', dir: 'ee')
end
end
......@@ -25,7 +25,7 @@ RSpec.describe IssueSerializer do
let(:serializer) { 'sidebar' }
it 'matches issue_sidebar json schema' do
expect(json_entity).to match_schema('entities/issue_sidebar', dir: 'ee')
expect(json_entity.to_json).to match_schema('entities/issue_sidebar', dir: 'ee')
end
end
......@@ -33,7 +33,7 @@ RSpec.describe IssueSerializer do
let(:serializer) { 'sidebar_extras' }
it 'matches issue_sidebar_extras json schema' do
expect(json_entity).to match_schema('entities/issue_sidebar_extras', dir: 'ee')
expect(json_entity.to_json).to match_schema('entities/issue_sidebar_extras', dir: 'ee')
end
end
end
......@@ -7,7 +7,7 @@ RSpec.describe StatusPage::IncidentSerializer do
shared_examples 'valid JSON schema' do |schema:|
it 'matches JSON schema' do
expect(json_entity).to match_schema(schema, dir: 'ee')
expect(json_entity.to_json).to match_schema(schema, dir: 'ee')
end
end
......
......@@ -3,7 +3,7 @@
"required": ["name", "scheduling_type"],
"properties": {
"name": { "type": "string" },
"scheduling_type": { "type": ["string", null] },
"scheduling_type": { "type": ["string", "null"] },
"needs": { "type": "array" }
},
"additionalProperties": false
......
......@@ -29,7 +29,7 @@
"web_url": { "type": "uri" },
"status_tooltip_html": { "type": ["string", "null"] },
"path": { "type": "string" }
},
},
"required": [
"id",
"state",
......@@ -39,8 +39,8 @@
"username"
]
},
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"system": { "type": "boolean" },
"noteable_id": { "type": "integer" },
"noteable_iid": { "type": ["integer", "null"] },
......@@ -48,7 +48,7 @@
"resolved": { "type": "boolean" },
"resolvable": { "type": "boolean" },
"resolved_by": { "type": ["string", "null"] },
"resolved_at": { "type": ["date", "null"] },
"resolved_at": { "type": ["string", "null"], "format": "date-time" },
"note": { "type": "string" },
"note_html": { "type": "string" },
"current_user": { "type": "object" },
......
......@@ -37,7 +37,7 @@
"properties" : {
"name": { "type": "string" },
"email": { "type": "string" },
"date": { "type": "date" },
"date": { "type": "string", "format": "date-time" },
"type": { "type": "string" }
},
"additionalProperties": false
......@@ -48,7 +48,7 @@
"properties" : {
"name": { "type": "string" },
"email": { "type": "string" },
"date": { "type": "date" },
"date": { "type": "string", "format": "date-time" },
"type": { "type": "string" }
},
"additionalProperties": false
......
......@@ -28,21 +28,9 @@
"merged": {
"type": "boolean"
},
"merged_at": {
"type": [
"date",
"null"
]
},
"closed_at": {
"type": [
"date",
"null"
]
},
"updated_at": {
"type": "date"
},
"merged_at": { "type": [ "string", "null" ], "format": "date-time" },
"closed_at": { "type": [ "string", "null" ], "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"assignee": {
"$ref": "user.json"
},
......
......@@ -24,7 +24,7 @@
"created_at": { "type": "date-time" },
"updated_at": { "type": "date-time" },
"branch_name": { "type": ["string", "null"] },
"due_date": { "type": "date" },
"due_date": { "type": ["string", "null"], "format": "date-time" },
"confidential": { "type": "boolean" },
"discussion_locked": { "type": ["boolean", "null"] },
"updated_by_id": { "type": ["integer", "null"] },
......
......@@ -6,7 +6,7 @@
"title": { "type": "string" },
"confidential": { "type": "boolean" },
"closed": { "type": "boolean" },
"due_date": { "type": "date" },
"due_date": { "type": ["string", "null"] },
"project_id": { "type": "integer" },
"relative_position": { "type": ["integer", "null"] },
"time_estimate": { "type": "integer" },
......
......@@ -6,7 +6,7 @@
"author_id": { "type": "integer" },
"project_id": { "type": "integer" },
"discussion_locked": { "type": ["boolean", "null"] },
"due_date": { "type": "date" },
"due_date": { "type": ["string", "null"], "format": "date-time" },
"confidential": { "type": "boolean" },
"reference": { "type": "string" },
"current_user": {
......
......@@ -39,18 +39,18 @@
"type": ["boolean"]
},
"environment": {
"type": ["string", null]
"type": ["string", "null"]
},
"tag_list": {
"type": ["array"],
"items": { "type": "string" }
},
"only": {
"type": ["array", "object", null],
"type": ["array", "object", "null"],
"items": { "type": ["string", "array"]}
},
"except": {
"type": ["array", "object", null],
"type": ["array", "object", "null"],
"items": { "type": ["string", "array"]}
}
},
......
......@@ -14,7 +14,7 @@
"type": "boolean"
},
"jobs": {
"type": ["array", null],
"type": ["array", "null"],
"items": {
"type": "object",
"$ref": "lint_job_entity.json"
......
......@@ -17,8 +17,8 @@
"state": { "type": "string" },
"iid": { "type": "integer" },
"confidential": { "type": "boolean" },
"created_at": { "type": "date" },
"due_date": { "type": ["date", "null"] }
"created_at": { "type": "string", "format": "date-time" },
"due_date": { "type": ["string", "null"], "format": "date-time" }
},
"additionalProperties": false
}
......@@ -16,8 +16,8 @@
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
"iid": { "type": "integer" },
"created_at": { "type": "date" },
"due_date": { "type": ["date", "null"] },
"created_at": { "type": "string" },
"due_date": { "type": ["string", "null"] },
"issues": {
"type": "array",
"items": { "$ref": "issue.json" }
......
......@@ -10,7 +10,7 @@
"id": { "type": "integer" },
"name": { "type": "string" },
"description": { "type": ["string", "null"] },
"created_at": { "type": "date" }
"created_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}
......@@ -14,7 +14,7 @@
"tag_name": { "type": "string" },
"name": { "type": ["string", "null"] },
"description": { "type": "string" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"project": { "$ref": "project.json" },
"milestones": {
"type": "array",
......
......@@ -8,8 +8,8 @@
"id": { "type": "integer" },
"iid": { "type": ["integer", "null"] },
"version": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"name": { "type": "string" },
"active": { "type": "boolean" },
"description": { "type": ["string", "null"] },
......
......@@ -10,8 +10,8 @@
"environment_scope": { "type": "string" },
"active": { "type": "boolean" },
"percentage": { "type": ["integer", "null"] },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"created_at": { "type": "string" },
"updated_at": { "type": "string" },
"strategies": { "type": "array", "items": { "$ref": "feature_flag_strategy.json" } }
},
"additionalProperties": false
......
......@@ -11,7 +11,7 @@
"project_id": { "type": ["integer", "null"] },
"title": { "type": "string" },
"confidential": { "type": "boolean" },
"due_date": { "type": ["date", "null"] },
"due_date": { "type": ["string", "null"] },
"relative_position": { "type": ["integer", "null"] },
"time_estimate": { "type": "integer" },
"issue_sidebar_endpoint": { "type": "string" },
......
......@@ -6,17 +6,21 @@
"ref": { "type": "string" },
"cron": { "type": "string" },
"cron_timezone": { "type": "string" },
"next_run_at": { "type": "date" },
"next_run_at": { "type": "string" },
"active": { "type": "boolean" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"last_pipeline": {
"created_at": { "type": ["string", "null"], "format": "date-time" },
"updated_at": { "type": ["string", "null"], "format": "date-time" },
"last_pipeline": {
"type": ["object", "null"],
"properties": {
"id": { "type": "integer" },
"project_id": { "type": "integer" },
"sha": { "type": "string" },
"ref": { "type": "string" },
"status": { "type": "string" }
"status": { "type": "string" },
"web_url": { "type": ["string", "null"] },
"created_at": { "type": ["string", "null"], "format": "date-time" },
"updated_at": { "type": ["string", "null"], "format": "date-time" }
},
"additionalProperties": false
},
......@@ -40,7 +44,7 @@
}
},
"required": [
"id", "description", "ref", "cron", "cron_timezone", "next_run_at",
"id", "description", "ref", "cron", "cron_timezone", "next_run_at",
"active", "created_at", "updated_at", "owner"
],
"additionalProperties": false
......
......@@ -30,6 +30,7 @@
"properties": {
"id": { "type": "integer" },
"avatar_url": { "type": ["string", "null"] },
"readme_url": { "type": ["string", "null"] },
"description": { "type": ["string", "null"] },
"default_branch": { "type": ["string", "null"] },
"tag_list": { "type": "array" },
......@@ -42,8 +43,9 @@
"path_with_namespace": { "type": "string" },
"star_count": { "type": "integer" },
"forks_count": { "type": "integer" },
"created_at": { "type": "date" },
"last_activity_at": { "type": "date" }
"created_at": { "type": "string", "format": "date-time" },
"namespace": {"type": "object" },
"last_activity_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
},
......@@ -70,7 +72,7 @@
"id": { "type": "integer" },
"color": {
"type": "string",
"pattern": "^#[0-9A-Fa-f]{3}{1,2}+$"
"pattern": "#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})"
},
"description": { "type": ["string", "null"] },
"name": { "type": "string" }
......
......@@ -19,7 +19,7 @@
"id": { "type": ["string", "null"] },
"short_id": { "type": ["string", "null"] },
"title": { "type": "string" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"parent_ids": {
"type": ["array", "null"],
"items": {
......@@ -30,10 +30,10 @@
"message": { "type": "string" },
"author_name": { "type": "string" },
"author_email": { "type": "string" },
"authored_date": { "type": "date" },
"authored_date": { "type": "string", "format": "date-time" },
"committer_name": { "type": "string" },
"committer_email": { "type": "string" },
"committed_date": { "type": "date" },
"committed_date": { "type": "string", "format": "date-time" },
"web_url": { "type": "string" }
}
}
......@@ -14,6 +14,6 @@
"line": { "type": ["integer", "null"] },
"line_type": { "type": ["string", "null"] },
"author": { "$ref": "user/basic.json" },
"created_at": { "type": "date" }
"created_at": { "type": "string", "format": "date-time" }
}
}
......@@ -17,9 +17,7 @@
"username": {
"type": "string"
},
"expires_at": {
"type": "date"
},
"expires_at": { "type": "string" },
"scopes": {
"type": "array",
"items": {
......
......@@ -6,8 +6,8 @@
"description": { "type": ["string", "null"] },
"active": {"type": "boolean" },
"version": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"scopes": { "type": "array", "items": { "$ref": "feature_flag_scope.json" } },
"strategies": { "type": "array", "items": { "$ref": "operations/strategy.json" } }
},
......
......@@ -13,8 +13,8 @@
"id": { "type": "integer" },
"environment_scope": { "type": "string" },
"active": { "type": "boolean" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"strategies": { "type": "array", "items": { "$ref": "feature_flag_strategy.json" } }
},
"additionalProperties": false
......
......@@ -9,8 +9,8 @@
"id": { "type": "integer" },
"environment_scope": { "type": "string" },
"active": { "type": "boolean" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"strategies": { "type": "array", "items": { "$ref": "feature_flag_strategy.json" } }
},
"additionalProperties": false
......
......@@ -8,9 +8,9 @@
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
"discussion_locked": { "type": ["boolean", "null"] },
"closed_at": { "type": "date" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"closed_at": { "type": ["string", "null"] },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"labels": {
"type": "array",
"items": {
......@@ -27,10 +27,10 @@
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"due_date": { "type": "date" },
"start_date": { "type": "date" }
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"due_date": { "type": "string" , "format": "date-time" },
"start_date": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
},
......@@ -83,7 +83,7 @@
"user_notes_count": { "type": "integer" },
"upvotes": { "type": "integer" },
"downvotes": { "type": "integer" },
"due_date": { "type": ["date", "null"] },
"due_date": { "type": ["string", "null"] },
"confidential": { "type": "boolean" },
"web_url": { "type": "uri" },
"time_stats": {
......
......@@ -15,8 +15,8 @@
"type": "string",
"enum": ["relates_to", "blocks", "is_blocked_by"]
},
"link_created_at": { "type": "date" },
"link_updated_at": { "type": "date" }
"link_created_at": { "type": "string" },
"link_updated_at": { "type": "string" }
},
"required" : [ "source_issue", "target_issue", "link_type" ]
}
......@@ -10,7 +10,7 @@
"avatar_url": { "type": ["string", "null"] },
"web_url": { "type": ["string", "null"] },
"access_level": { "type": "integer" },
"expires_at": { "type": ["date", "null"] },
"expires_at": { "type": ["string", "null"], "format": "date-time" },
"is_using_seat": { "type": "boolean" }
},
"required": [
......
......@@ -20,7 +20,7 @@
},
"additionalProperties": false
},
"merged_at": { "type": ["date", "null"] },
"merged_at": { "type": ["string", "null"] },
"closed_by": {
"type": ["object", "null"],
"properties": {
......@@ -33,9 +33,9 @@
},
"additionalProperties": false
},
"closed_at": { "type": ["date", "null"] },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"closed_at": { "type": ["string", "null"], "format": "date-time" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"target_branch": { "type": "string" },
"source_branch": { "type": "string" },
"upvotes": { "type": "integer" },
......@@ -88,10 +88,10 @@
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"due_date": { "type": "date" },
"start_date": { "type": "date" }
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"due_date": { "type": "string", "format": "date-time" },
"start_date": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
},
......
......@@ -8,8 +8,8 @@
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"web_url": { "type": "uri" }
},
"required": [
......
......@@ -8,10 +8,10 @@
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"start_date": { "type": "date" },
"due_date": { "type": "date" },
"created_at": { "type": "string" },
"updated_at": { "type": "string" },
"start_date": { "type": ["string", "null"], "format": "date-time" },
"due_date": { "type": ["string", "null"], "format": "date-time" },
"expired": { "type": ["boolean", "null"] },
"web_url": { "type": "string" }
},
......
......@@ -8,10 +8,10 @@
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"start_date": { "type": "date" },
"due_date": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"start_date": { "type": ["string", "null"], "format": "date-time" },
"due_date": { "type": ["string", "null"], "format": "date-time" },
"expired": { "type": ["boolean", "null"] },
"web_url": { "type": "string" },
"issue_stats": {
......
......@@ -22,8 +22,8 @@
]
},
"commands_changes": { "type": "object", "additionalProperties": true },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"system": { "type": "boolean" },
"noteable_id": { "type": "integer" },
"noteable_iid": { "type": "integer" },
......@@ -31,7 +31,7 @@
"resolved": { "type": "boolean" },
"resolvable": { "type": "boolean" },
"resolved_by": { "type": ["string", "null"] },
"resolved_at": { "type": ["date", "null"] },
"resolved_at": { "type": ["string", "null"] },
"confidential": { "type": ["boolean", "null"] }
},
"required": [
......
......@@ -2,7 +2,6 @@
"type": "object",
"required": ["count", "items"],
"properties": {
"count": { "const": 0 },
"items": {
"type": "array",
"items": {
......
......@@ -6,7 +6,7 @@
"project_id": { "type": "integer" },
"verified": { "type": "boolean" },
"verification_code": { "type": ["string", "null"] },
"enabled_until": { "type": ["date", "null"] },
"enabled_until": { "type": ["string", "null"], "format": "date-time" },
"auto_ssl_enabled": { "type": "boolean" },
"certificate_expiration": {
"type": "object",
......
......@@ -5,7 +5,7 @@
"url": { "type": "uri" },
"verified": { "type": "boolean" },
"verification_code": { "type": ["string", "null"] },
"enabled_until": { "type": ["date", "null"] },
"enabled_until": { "type": ["string", "null"] },
"auto_ssl_enabled": { "type": "boolean" },
"certificate": {
"type": "object",
......
......@@ -13,11 +13,11 @@
{ "$ref": "../user/basic.json" }
]
},
"created_at": { "type": ["date", "null"] },
"updated_at": { "type": ["date", "null"] },
"started_at": { "type": ["date", "null"] },
"finished_at": { "type": ["date", "null"] },
"committed_at": { "type": ["date", "null"] },
"created_at": { "type": ["string", "null"], "format": "date-time" },
"updated_at": { "type": ["string", "null"], "format": "date-time" },
"started_at": { "type": ["string", "null"], "format": "date-time" },
"finished_at": { "type": ["string", "null"], "format": "date-time" },
"committed_at": { "type": ["string", "null"], "format": "date-time" },
"duration": { "type": ["number", "null"] },
"coverage": { "type": ["string", "null"] },
"detailed_status": {
......
......@@ -16,6 +16,6 @@
"name_with_namespace": { "type": "string" },
"path": { "type": "string" },
"path_with_namespace": { "type": "string" },
"created_at": { "type": "date" }
"created_at": { "type": "string", "format": "date-time" }
}
}
......@@ -10,7 +10,7 @@
],
"properties" : {
"id": { "type": "integer" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"state": { "type": "string" },
"source_storage_name": { "type": "string" },
"destination_storage_name": { "type": "string" },
......
......@@ -9,7 +9,7 @@
"description": { "type": ["string", "null"] },
"path": { "type": "string" },
"path_with_namespace": { "type": "string" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"default_branch": { "type": ["string", "null"] },
"tag_list": {
"type": "array",
......@@ -24,7 +24,7 @@
"avatar_url": { "type": ["string", "null"] },
"star_count": { "type": "integer" },
"forks_count": { "type": "integer" },
"last_activity_at": { "type": "date" },
"last_activity_at": { "type": "string", "format": "date-time" },
"namespace": {
"type": "object",
"properties" : {
......
......@@ -6,8 +6,8 @@
"tag_name": { "type": "string" },
"description": { "type": "string" },
"description_html": { "type": "string" },
"created_at": { "type": "date" },
"released_at": { "type": "date" },
"created_at": { "type": "string" , "format": "date-time"},
"released_at": { "type": "string", "format": "date-time" },
"upcoming_release": { "type": "boolean" },
"commit": {
"oneOf": [{ "type": "null" }, { "$ref": "commit/basic.json" }]
......
......@@ -8,7 +8,7 @@
"properties" : {
"sha": { "type": "string" },
"filepath": { "type": "string" },
"collected_at": { "type": "date" }
"collected_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}
......@@ -5,8 +5,8 @@
"name": { "type": "string" },
"description": { "type": "string" },
"description_html": { "type": "string" },
"created_at": { "type": "date" },
"released_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"released_at": { "type": "string", "format": "date-time" },
"upcoming_release": { "type": "boolean" },
"milestones": {
"type": "array",
......
......@@ -10,7 +10,7 @@
],
"properties" : {
"id": { "type": "integer" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"state": { "type": "string" },
"source_storage_name": { "type": "string" },
"destination_storage_name": { "type": "string" },
......
......@@ -21,8 +21,8 @@
"visibility": { "type": "string" },
"web_url": { "type": "string" },
"raw_url": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"author": {
"type": "object",
"properties": {
......
......@@ -41,7 +41,7 @@
},
"avatar_url": { "type": "string" },
"web_url": { "type": "string" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"bio": { "type": ["string", "null"] },
"location": { "type": ["string", "null"] },
"skype": { "type": "string" },
......@@ -49,11 +49,11 @@
"twitter": { "type": "string "},
"website_url": { "type": "string" },
"organization": { "type": ["string", "null"] },
"last_sign_in_at": { "type": "date" },
"confirmed_at": { "type": ["date", "null"] },
"last_sign_in_at": { "type": ["string", "null"], "format": "date-time" },
"confirmed_at": { "type": ["string", "null"] },
"color_scheme_id": { "type": "integer" },
"projects_limit": { "type": "integer" },
"current_sign_in_at": { "type": "date" },
"current_sign_in_at": { "type": ["string", "null"], "format": "date-time" },
"identities": {
"type": "array",
"items": {
......
......@@ -29,9 +29,7 @@
"total_size": {
"type": "integer"
},
"created_at": {
"type": "date"
},
"created_at": { "type": "string", "format": "date-time" },
"destroy_path": {
"type": "string"
}
......
......@@ -7,7 +7,7 @@
"ref": { "type": "string "},
"description": { "type": "string" },
"description_html": { "type": "string" },
"created_at": { "type": "date" },
"created_at": { "type": "string", "format": "date-time" },
"commit": {
"oneOf": [{ "type": "null" }, { "$ref": "public_api/v4/commit/basic.json" }]
},
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [],
"properties": {
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"type", "options"
......@@ -6,7 +7,7 @@
"properties": {
"type": { "enum": ["custom"] },
"label": { "type": "string" },
"options": { "$ref": "custom_variable_options.json" }
"options": { "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/custom_variable_options.json" }
},
"additionalProperties": false
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["values"],
"properties": {
"values": {
"type": "array",
"items": { "$ref": "custom_variable_values.json" }
"items": { "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/custom_variable_values.json" }
}
},
"additionalProperties": false
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["value"],
"properties": {
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"dashboard",
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["panel_groups"],
"properties": {
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["panels"],
"properties": {
"panels": {
"type": "array",
"items": { "$ref": "panels.json" }
"items": { "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/panels.json" }
}
},
"additionalProperties": false
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"required": ["url"],
"properties": {
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"type", "options"
......@@ -6,7 +7,7 @@
"properties": {
"type": { "enum": "metric_label_values" },
"label": { "type": "string" },
"options": { "$ref": "metric_label_values_variable_options.json" }
"options": { "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metric_label_values_variable_options.json" }
},
"additionalProperties": false
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"series_selector", "label", "prometheus_endpoint_path"
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"label",
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"group",
......@@ -8,7 +9,7 @@
"group": { "type": "string" },
"panels": {
"type": "array",
"items": { "$ref": "panels.json" }
"items": { "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/panels.json" }
},
"has_custom_metrics": { "type": "boolean" }
},
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"title",
......@@ -10,11 +11,11 @@
"id": { "type": "string" },
"type": { "type": "string" },
"y_label": { "type": "string" },
"y_axis": { "$ref": "axis.json" },
"y_axis": { "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/axis.json" },
"max_value": { "type": "number" },
"metrics": {
"type": "array",
"items": { "$ref": "metrics.json" }
"items": { "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json" }
}
},
"additionalProperties": false
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["variables"],
"properties": {
"variables": { "$ref": "variables.json" }
"variables": { "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/variables.json" }
},
"additionalProperties": false
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"type", "options"
......@@ -6,7 +7,7 @@
"properties": {
"type": { "enum": ["text"] },
"label": { "type": "string" },
"options": { "$ref": "text_variable_options.json" }
"options": { "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/text_variable_options.json" }
},
"additionalProperties": false
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"default_value": { "type": "string" }
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9_]*$": {
"anyOf": [
{ "$ref": "text_variable_full_syntax.json" },
{ "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/text_variable_full_syntax.json" },
{ "type": "string" },
{
"type": "array",
"items": { "type": "string" }
},
{ "$ref": "custom_variable_full_syntax.json" },
{ "$ref": "metric_label_values_variable_full_syntax.json" }
{ "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/custom_variable_full_syntax.json" },
{ "$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metric_label_values_variable_full_syntax.json" }
]
}
},
......
......@@ -17,8 +17,8 @@ RSpec.describe ::Packages::Npm::PackagePresenter do
context 'for packages without dependencies' do
it { is_expected.to be_a(Hash) }
it { expect(subject[package1.version]).to match_schema('public_api/v4/packages/npm_package_version') }
it { expect(subject[package2.version]).to match_schema('public_api/v4/packages/npm_package_version') }
it { expect(subject[package1.version].with_indifferent_access).to match_schema('public_api/v4/packages/npm_package_version') }
it { expect(subject[package2.version].with_indifferent_access).to match_schema('public_api/v4/packages/npm_package_version') }
described_class::NPM_VALID_DEPENDENCY_TYPES.each do |dependency_type|
it { expect(subject.dig(package1.version, dependency_type)).to be nil }
......@@ -32,8 +32,8 @@ RSpec.describe ::Packages::Npm::PackagePresenter do
end
it { is_expected.to be_a(Hash) }
it { expect(subject[package1.version]).to match_schema('public_api/v4/packages/npm_package_version') }
it { expect(subject[package2.version]).to match_schema('public_api/v4/packages/npm_package_version') }
it { expect(subject[package1.version].with_indifferent_access).to match_schema('public_api/v4/packages/npm_package_version') }
it { expect(subject[package2.version].with_indifferent_access).to match_schema('public_api/v4/packages/npm_package_version') }
described_class::NPM_VALID_DEPENDENCY_TYPES.each do |dependency_type|
it { expect(subject.dig(package1.version, dependency_type.to_s)).to be_any }
end
......
......@@ -74,7 +74,7 @@ module Atlassian
'deploymentSequenceNumber' => { 'type' => 'integer' },
'updateSequenceNumber' => { 'type' => 'integer' },
'associations' => {
'type' => 'array',
'type' => %w(array),
'items' => association_type,
'minItems' => 1
},
......
# frozen_string_literal: true
module SchemaPath
@schema_cache = {}
def self.expand(schema, dir = nil)
return schema unless schema.is_a?(String)
......@@ -12,38 +14,47 @@ module SchemaPath
Rails.root.join(dir.to_s, 'spec', "fixtures/api/schemas/#{schema}.json").to_s
end
end
RSpec::Matchers.define :match_response_schema do |schema, dir: nil, **options|
match do |response|
@errors = JSON::Validator.fully_validate(
SchemaPath.expand(schema, dir), response.body, options)
def self.validator(schema_path)
unless @schema_cache.key?(schema_path)
@schema_cache[schema_path] = JSONSchemer.schema(schema_path, ref_resolver: SchemaPath.file_ref_resolver)
end
@errors.empty?
@schema_cache[schema_path]
end
failure_message do |response|
"didn't match the schema defined by #{SchemaPath.expand(schema, dir)}" \
" The validation errors were:\n#{@errors.join("\n")}"
def self.file_ref_resolver
proc do |uri|
file = Rails.root.join(uri.path)
raise StandardError, "Ref file #{uri.path} must be json" unless uri.path.ends_with?('.json')
raise StandardError, "File #{file.to_path} doesn't exists" unless file.exist?
Gitlab::Json.parse(File.read(file))
end
end
end
RSpec::Matchers.define :match_schema do |schema, dir: nil, **options|
match do |data|
@errors = JSON::Validator.fully_validate(
SchemaPath.expand(schema, dir), data, options)
RSpec::Matchers.define :match_response_schema do |schema, dir: nil, **options|
match do |response|
schema_path = Pathname.new(SchemaPath.expand(schema, dir))
validator = SchemaPath.validator(schema_path)
@errors.empty?
end
data = Gitlab::Json.parse(response.body)
failure_message do |response|
"didn't match the schema defined by #{schema_name(schema, dir)}" \
" The validation errors were:\n#{@errors.join("\n")}"
validator.valid?(data)
end
end
def schema_name(schema, dir)
return 'provided schema' unless schema.is_a?(String)
SchemaPath.expand(schema, dir)
RSpec::Matchers.define :match_schema do |schema, dir: nil, **options|
match do |data|
schema = SchemaPath.expand(schema, dir)
schema = Pathname.new(schema) if schema.is_a?(String)
validator = SchemaPath.validator(schema)
if data.is_a?(String)
validator.valid?(Gitlab::Json.parse(data))
else
validator.valid?(data)
end
end
end
......@@ -14,7 +14,6 @@ RSpec.shared_examples 'multiple and scoped issue boards' do |route_definition|
post api(root_url, user), params: { name: "new board" }
expect(response).to have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/board', dir: "ee")
end
end
......
......@@ -12,13 +12,22 @@ RSpec.shared_examples 'misconfigured dashboard service response' do |status_code
end
RSpec.shared_examples 'valid dashboard service response for schema' do
file_ref_resolver = proc do |uri|
file = Rails.root.join(uri.path)
raise StandardError, "Ref file #{uri.path} must be json" unless uri.path.ends_with?('.json')
raise StandardError, "File #{file.to_path} doesn't exists" unless file.exist?
Gitlab::Json.parse(File.read(file))
end
it 'returns a json representation of the dashboard' do
result = service_call
expect(result.keys).to contain_exactly(:dashboard, :status)
expect(result[:status]).to eq(:success)
expect(JSON::Validator.fully_validate(dashboard_schema, result[:dashboard])).to be_empty
validator = JSONSchemer.schema(dashboard_schema, ref_resolver: file_ref_resolver)
expect(validator.valid?(result[:dashboard].with_indifferent_access)).to be true
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment